Custom Query and Model in Django - python

I want to create a custom model with methods that connect to an existing DB and return data based on custom queries injected into Django. I am obviously having some problems with this, and am wondering if this is possible with my current approach. I feel like this is either a trivial question or I am misunderstanding something fundamental here. Here is my code so far:
from django.db import models
import datetime
from django.utils import timezone
class data_model(models.Field):
description = "return and create data objects for visulaizations"
def __init__(self, days, action):
self.days = days
self.action = action
if(self.action == ""):
self.action = "inspections"
getVioPoints(self.action)
def getVioPoints(self):
#get points query here and get data from db
return self
Within getVioPoints, I want to create a query string - like what you would see in a PHP $query = "select tuples where what I want = something" type of situation. Then return the data in a way that my template views can access it like so:
<ul>
{% for choice in data_returned %}
<li> {% choice.title %} </li>
{% endfor %}
</ul>
Any ideas? Any assistance would be greatly appreciated.
Thanks.

You can make custom query and put result into json.
You can read about custom queries here:https://docs.djangoproject.com/en/dev/topics/db/sql/#executing-custom-sql-directly,
but this isn`t django-way - you just ignore orm layer and have to write all sql queries by yourself, I recommend you to create model, connect it to db and make queries through orm.

Related

Optimise django manytomany relation

I was wondering if there is a way to make this more optimised.
class AppTopic(models.Model):
topic = models.CharField(max_length=20) # lowercase (cookies)
class UserTopic(models.Model):
topic = models.CharField(max_length=20) # Any case (cOoKiEs)
app_topic = models.ForeignKey(AppTopic) # related to (cookies -> lowercase version of cOoKiEs)
class User(models.Model):
topics = models.ManyToManyField(UserTopic) # AppTopic stored with any case
The goal is to have all AppTopics be lowercase on the lowest level, but I want to allow users to chose what capitalisation they want. In doing so I still want to keep the relation with it's lowercase version. The topic on the lowest level could be cookies, the user might pick cOoKiEs which should still be related to the orignal cookies.
My current solution works, but requires an entirely new table with almost no use. I will continue using this if there isn't really a smarter way to do it.
There's nothing in the Django model API that would allow you to manipulate values from the models themselves. If you don't want to change the value in the database or in the model instance, you can change how it displays on the template level using the
lower filter in Django template language.
<body>
<div>
{% if condition %}
<h1>{{AppTopic|lower}}</h1>
{% else %}
<h1>{{AppTopic|??}}</h1> #AppTopic but camelcase. There's no camelcase filter in Django
{% endif %}
</div>
</body
Views.py
def View(request, condition)
...
return render(request, 'template.html', {condition:'condition'})

How to query in django one to many

What I want to do?
I have an app have three models:Series,Section and Episode,every one have a one-many query(by ForeignKey). just like this
series-> many Section,section-> many Episode
Now I will show a section with episodes information in series page, but it make more query.
now code
views.py
series = Series.objects.get(id=series_id)
section = Section.objects.filter(series=series)
list.html
{% for item in sections %}
...
{% for episode in item.episode_set.all %}
...
{% endfor %}
...
{%endfor%}
models.py
class Section(models.Model):
series = models.ForeignKey(Series)
....
class Episode(models.Model):
section = models.ForeignKey(Section)
What I want to get ?
an example code tell me how to query in views.py and use just little query.
you can guess, in my code, if here are many section and many episode, it will have many query.
Some idea.
I use Laravel Before, In Laravel , it has a hasMany Function, I can use it to get other models items(Define by belongsTo).
Is Django has same function?
If in template you need only episodes, you can query just them with single query
Episode.objects.filter(section__series=series_id)
But if you need all data then you can use prefetch_related Django docs.
The simplest example looks enough for your code
series = Series.objects.filter(id=series_id).prefetch_related('section_set', 'section_set__episode_set').get()
After this calls to series.section_set.all() and to section.episode_set.all() will not produce extra query.

Displaying multiple objects in a DetailView

I have been dabbling with Django CBV lately and have a question. Maybe you have better ideas than I.
Assume I have a airline booking CRM application and I intend to perform a display of a customer for various things. Assume I have a list of Models, for a Customer like Booking, Rating, Customer_Service_Calls, Favourited_Route.
Now, given a DetailView implemented by Django's CBV, I have something like this
class CustomerThreeSixtyView(DetailView):
model = 'Customer'
def get_context_data(self, **kwargs):
context = super(CustomerThreeSixtyView, self).get_context_data(**kwargs)
context['bookings'] = Booking.objects.all.filter(customer_id=request.kwargs['pk']
context['ratings'] = Ratings.objects.all.filter(customer_id=request.kwargs['pk']
context['calls'] = Customer_Service_Calls.objects.all.filter(customer_id=request.kwargs['pk'], status'Open')
context['fav_routes'] = Favourited_Route.objects.all.filter(customer_id=request.kwargs['pk'], status'Open')
return context
Something like this. My question is that, are there better ways to do this? This is the most straightforward way but I'm asking for suggestions because there seem to be bound for something.
What you have done already looks good enough. You are getting what you required in the context and then using it in the template to show the information.
Alternatively, you could directly access bookings for a particular customer in the template without specifying it in the context:
{% for booking in object.booking_set.all %} # object is the customer here
# do what you want to do with the booking here
{% endfor %}
It is even better if you use related_name while linking the customer to Booking:
class Booking(models.Model):
customer = models.ForeignKey(Customer, related_name='bookings')
# other fields
Now, you can directly use the defined related_name to access the bookings for a particular customer:
{% for booking in object.bookings.all %}
# do what you want to do with the booking here
{% endfor %}
And, you can use the same approach for other classes such as Rating, Customer_Service_Calls, Favourited_Route etc.

Pagination of Date-Based Generic Views in Django

I have a pretty simple question. I want to make some date-based generic views on a Django site, but I also want to paginate them. According to the documentation the object_list view has page and paginate_by arguments, but the archive_month view does not. What's the "right" way to do it?
I created a template tag to do template-based pagination on collections passed to the templates that aren't already paginated. Copy the following code to an app/templatetags/pagify.py file.
from django.template import Library, Node, Variable
from django.core.paginator import Paginator
import settings
register = Library()
class PagifyNode(Node):
def __init__(self, items, page_size, varname):
self.items = Variable(items)
self.page_size = int(page_size)
self.varname = varname
def render(self, context):
pages = Paginator(self.items.resolve(context), self.page_size)
request = context['request']
page_num = int(request.GET.get('page', 1))
context[self.varname] = pages.page(page_num)
return ''
#register.tag
def pagify(parser, token):
"""
Usage:
{% pagify items by page_size as varname %}
"""
bits = token.contents.split()
if len(bits) != 6:
raise TemplateSyntaxError, 'pagify tag takes exactly 5 arguments'
if bits[2] != 'by':
raise TemplateSyntaxError, 'second argument to pagify tag must be "by"'
if bits[4] != 'as':
raise TemplateSyntaxError, 'fourth argument to pagify tag must be "as"'
return PagifyNode(bits[1], bits[3], bits[5])
To use it in the templates (assume we've passed in an un-paginated list called items):
{% load pagify %}
{% pagify items by 20 as page %}
{% for item in page %}
{{ item }}
{% endfor %}
The page_size argument (the 20) can be a variable as well. The tag automatically detects page=5 variables in the querystring. And if you ever need to get at the paginator that belong to the page (for a page count, for example), you can simply call:
{{ page.paginator.num_pages }}
Date based generic views don't have pagination. It seems you can't add pagination via wrapping them as well since they return rendered result.
I would simply write my own view in this case. You can check out generic views' code as well, but most of it will probably be unneeded in your case.
Since your question is a valid one, and looking at the code; I wonder why they didn't decouple queryset generation as separate functions. You could just use them and render as you wish then.
I was working on a problem similar to this yesterday, and I found the best solution for me personally was to use the object_list generic view for all date-based pages, but pass a filtered queryset, as follows:
import datetime, time
def post_archive_month(request, year, month, page=0, template_name='post_archive_month.html', **kwargs):
# Convert date to numeric format
date = datetime.date(*time.strptime('%s-%s' % (year, month), '%Y-%b')[:3])
return list_detail.object_list(
request,
queryset = Post.objects.filter(publish__year=date.year, publish__date.month).order_by('-publish',),
paginate_by = 5,
page = page,
template_name = template_name,
**kwargs)
Where the urls.py reads something like:
url(r'^blog/(?P<year>\d{4})/(?P<month>\w{3})/$',
view=path.to.generic_view,
name='archive_month'),
I found this the easiest way around the problem without resorting to hacking the other generic views or writing a custom view.
There is also excellent django-pagination add-on, which is completely independent of underlying view.
Django date-based generic views do not support pagination. There is an open ticket from 2006 on this. If you want, you can try out the code patches supplied to implement this feature. I am not sure why the patches have not been applied to the codebase yet.

Django - queries made repeat/inefficient

Alright, I have a Django view, like this:
#render_to('home/main.html')
def login(request):
# also tried Client.objects.select_related().all()
clients = Client.objects.all()
return {'clients':clients}
And I have a template, main.html, like this:
<ul>
{% for client in clients %}
<li>{{ client.full_name }}</li>
<ul>
{% for pet in client.pets.all %}
<li>{{ pet.full_name }}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
I also print out all the queries in sql_queries at the bottom of my base template. When I run this view, the following queries are made:
SELECT `home_client`.`id`, ... FROM `home_client`;
SELECT `home_pet`.`id`, ... FROM `home_pet` WHERE `home_pet`.`client_id` = 1;
SELECT `home_client`.`id`, ... FROM `home_client` WHERE `home_client`.`id` = 1;
SELECT `home_client`.`id`, ... FROM `home_client` WHERE `home_client`.`id` = 1;
SELECT `home_pet`.`id`, ... FROM `home_pet` WHERE `home_pet`.`client_id` = 2;
SELECT `home_client`.`id`, ... FROM `home_client` WHERE `home_client`.`id` = 2;
My question is, why are all these queries being made? Shouldn't it just be 1 query to retrieve all the clients and a query per client to retrieve all the pets from each client? I have 2 clients in the home_client table, so it should be 3 queries total. Most troubling of all is that queries 3 and 4 are 100% identical. I don't want to "prematurely optimize" or anything but I do want to make sure Django isn't being wildly inefficient. Any help on this would be appreciated. Thanks.
Django uses a cache. The RDBMS uses a cache. Don't prematurely optimize the queries.
You can play with bulk queries in your view function instead of one-at-a-time queries in your template.
#render_to('home/main.html')
def login(request):
# Query all clients
clients = Client.objects.all()
# Assemble an in-memory table of pets
pets = collections.defaultdict(list)
for p in Pet.objects.all():
pets[pet.client].append(p)
# Create clients and pets tuples
clientsPetTuples = [ (c,pets[c]) for c in clients ]
return {'clientPets': clientsPetTuples}
However, you don't seem to have any evidence that your template is the slowest part of your application.
Further, this trades off giant memory use against SQL use. Until you have measurements that prove that your template queries are actually slow, you shouldn't be over thinking the SQL.
Don't worry about the SQL until you have evidence.
try using Client.objects.all().select_related()
This will automagically also cache related models in a single database query.
Does Client 1 have 2 Pets and Client 2 have 1 Pet?
If so, that would indicate to me that Pet.full_name or something else you're doing in the Pet display loop is trying to access its related Client's details. Django's ORM doesn't use an identity map, so accessing the Client foreign key from any of your Pet objects would require hitting the database again to retrieve that Client.
P.S. select_related won't have any effect on the data you're using in this scenario as it only follows foreign-key relationships, but the pet-to-client relationship is many-to-one.
Update: if you want to avoid having to change the logic in Pet.full_name or having to perform said logic in the template instead for this case, you could alter the way you get a handle on each Client's Pets in order to prefill the ForeignKey cache with for each Pet with its Client:
class Client(models.Model):
# ...
def get_pets(self):
for pet in self.pets.all():
setattr(pet, '_client_cache', self)
yield pet
...where the 'client' part of '_client_cache' is whatever attribute name is used in the Pet class for the ForeignKey to the Pet's Client. This takes advantage of the way Django implements access to ForeignKey-related objects using its SingleRelatedObjectDescriptor class, which looks for this cache attribute before querying the database.
Resulting template usage:
{% for pet in client.get_pets %}
...
{% endfor %}

Categories