I am using the standard User model (django.contrib.auth) which comes with Django. I have made some of my own models in a Django application and created a relationship between like this:
from django.db import models
from django.contrib.auth.models import User
class GroupMembership(models.Model):
user = models.ForeignKey(User, null = True, blank = True, related_name='memberships')
#other irrelevant fields removed from example
So I can now do this to get all of a user's current memberships:
user.memberships.all()
However, I want to be able to do a more complex query, like this:
user.memberships.all().select_related('group__name')
This works fine but I want to fetch this data in a template. It seems silly to try to put this sort of logic inside a template (and I can't seem to make it work anyway), so I want to create a better way of doing it. I could sub-class User, but that doesn't seem like a great solution - I may in future want to move my application into other Django sites, and presumably if there was any another application that sub-classed User I wouldn't be able to get it to work.
Is the best to create a method inside GroupMembership called something like get_by_user(user)? Would I be able to call this from a template?
I would appreciate any advice anybody can give on structuring this - sorry if this is a bit long/vague.
First, calling select_related and passing arguments, doesn't do anything. It's a hint that cache should be populated.
You would never call select_related in a template, only a view function. And only when you knew you needed all those related objects for other processing.
"Is the best to create a method inside GroupMembership called something like get_by_user(user)?"
You have this. I'm not sure what's wrong with it.
GroupMembership.objects.filter( user="someUser" )
"Would I be able to call this from a template?"
No. That's what view functions are for.
groups = GroupMembership.objects.filter( user="someUser" )
Then you provide the groups object to the template for rendering.
Edit
This is one line of code; it doesn't seem that onerous a burden to include this in all your view functions.
If you want this to appear on every page, you have lots of choices that do not involve repeating this line of code..
A view function can call another function.
You might want to try callable objects instead of simple functions; these can subclass a common callable object that fills in this information.
You can add a template context processor to put this into the context of all templates that are rendered.
You could write your own decorator to assure that this is done in every view function that has the decorator.
Related
Trying to implement a simple ordering query on ProductCategoryView in Django-Oscar. It should be fairly simple to implement but it's taking too much time to understand. I'm having second thoughts to go forward with Oscar or not as it seems difficult to extend.
The ProductCategoryView returns products of a certain category. I want to sort them according to certain field in product model say price. First I change the parent generic class from TemplateView to ListView so that I can use get_queryset method. Then I override the get_queryset method as below and write a simple queryset in that. Still the sorting doesn't happen though the flow does go inside the get_queryset method.
def get_queryset(self):
queryset = Product.objects.filter(categories = self.category)
logger.debug("inside")
queryset = queryset.order_by("price")
return queryset
So what methods I have to overwrite. Will there be so much trouble editing Oscar every time or I'm missing something?
P.S : I have asked lot of questions around Django/Oscar Class based view recently . So I might look like a Help Vampire. Please ignore this question if that is the case.
#Anentropic is right but let me elaborate a bit.
Oscar bases all its browse views on search engines so faceting can be used to narrow down the list of products returned. By default there are search engine integrations for Solr and Elasticsearch.
If you don't use Solr or Elasticsearch, the default implementation is SimpleProductSearchHandler. It does not use any external services but instead calls Product.browsable.get_queryset(). That code lives in oscar.apps.catalogue.managers and could be customized to provide custom ordering.
This is all assuming you don't want to use a search engine as customizations required to change the order of results for other search handler classes are backend-specific.
If I do the folllowing:
obj = Model.objects.get(pk=2)
object.field = 'new value'
object.save()
It runs the custom save method that I have written in django.
However, if I do a normal update statement:
Model.objects.filter(pk=2).update(field='new value')
It does not use the custom save method. My question here is two-fold:
1) Why was that decision made in django -- why doesn't every 'save' implement the custom save method.
2) Is there a codebase-wide way to make sure that no update statements are ever made? Basically, I just want to ensure that the custom save method is always run whenever doing a save within the django ORM. How would this be possible?
I'm not a Django developer, but I dabble from time to time and no one else has answered yet.
Why was that decision made in django -- why doesn't every 'save' implement the custom save method.
I'm going to guess here that this is done as a speed optimization for the common case of just performing a bulk update. update works on the SQL level so it is potentially much faster than calling save on lots of objects, each one being its own database transaction.
Is there a codebase-wide way to make sure that no update statements are ever made? Basically, I just want to ensure that the custom save method is always run whenever doing a save within the django ORM. How would this be possible?
You can use a custom manager with a custom QuerySet that raises some Exception whenever update is called. Of course, you can always loop over the Queryset and call save on each object if you need the custom behavior.
Forbidding Update on a Model
from django.db import models
class NoUpdateQuerySet(models.QuerySet):
"""Don't let people call update! Muahaha"""
def update(self, **kwargs):
# you should raise a more specific Exception.
raise Exception('You shall not update; use save instead.')
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
# setting the custom manager keeps people from calling update.
objects = NoUpdateQuerySet.as_manager()
You would just need to set the NoUpdateQuerySet as a manager for each model you don't want to update. I don't really think it's necessary to set a custom QuerySet though; if it were me I would just not call update, and loop through the objects that need to be saved whenever I need to. You may find a time when you want to call update, and this would end up being very annoying.
Forbidding Update Project-Wide
If you really really decide you hate update, you can just monkey-patch the update method. Then you can be completely certain it's not being called. You can monkey-patch it in your project's settings.py, since you know that module will be imported:
def no_update(self, **kwargs):
# probably want a more specific Exception
raise Exception('NO UPDATING HERE')
from django.db.models.query import QuerySet
QuerySet.update = no_update
Note that the traceback will actually be pretty confusing, since it will point to a function in settings.py. I'm not sure how much, if ever, update is used by other apps; this could have unintended consequences.
I have newfies dialer project, i would like to add a new field in Call Reports section.
I have lot of field that are unused in contact model. One of them can be used for this special id for my purpose.
How can i do that? Please help me anyone who familiar with newfies-dialer.
Newfies-Dialer is based on the Django framework, so it's good to know about Django to hack on the project.
You will notice in Newfies-Dialer that there is a template called: dialer_cdr/templates/dialer_cdr/voipcall_report.html
in which we display the data that is passed from the view.
So then in dialer_cdr/views.py, you have a view function which is in charge of rendering template and pass it some data. There, you can either modify voipcall_list object to add extra data to it, like info from the contact model, or pass an other object to data.
Here a link to the function handling this view: https://github.com/Star2Billing/newfies-dialer/blob/v2.12.2/newfies/dialer_cdr/views.py#L169
I would like to view some user information on over half of my website's views.
This information should contain not only trivial username but also some fields from other tables of my project that are associated with current user.
I would also like to put this information into the template that my current view extends, just to keep it DRY.
I already did some research and coded some templatetags hoping that registering tags would help me achieve this but I have no idea how to get user information when there's no request like in views' functions.
Any tips on how to achieve this will be much appreciated. I just started django yesterday and am still a bit confused by it's philosophy.
You can use a context processor to add data to the template context in a DRY way.
In a nutshell, a context processor is simply a function that accepts a request as its first argument, does some additional processing that you add and augments the context with whatever values you want.
You can query an objects models, add the current datetime...pretty much anything you can do with Python or Django can go into a context processor.
I was looking over the Django documentation on a way to do this but didn't see anything, though I may have missed it as I'm not sure exactly where to look... I want to be able to perform a specific action on every user request, such as instantiating a class and calling one of its functions, however the only way I know of to do this now is to put it in each view function. Is there a better way to do this, any advice is appreciated.
You want to use Django's middleware functionality.