Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I want to have sortable columns in my tables (just like what is done for the admin changelists)....I'm looking for a solution that will be easy to implement and customize if I want.
How can I do this?
If you use pagination rather than a Javascript table sorter, it might not be sufficient or behave unexpected.
Create every column header as a link e.g.
<th>Name</th>
and in your view you check whether the order_by parameter is set or not:
order_by = request.GET.get('order_by', 'defaultOrderField')
Model.objects.all().order_by(order_by)
Javascript? There are plenty of table sorters out there:
http://tablesorter.com/docs/
http://kryogenix.org/code/browser/sorttable/
http://friedcellcollective.net/js/SortedTable/
http://www.leigeber.com/2009/03/table-sorter/
http://www.millstream.com.au/view/code/tablekit
I used the approach followed by the most voted answer above. But I solve the ascending/descending ordering when clicking multiple times on the column header by using a custom tag.
The tag:
from urllib.parse import urlencode
from collections import OrderedDict
#register.simple_tag
def url_replace(request, field, value, direction=''):
dict_ = request.GET.copy()
if field == 'order_by' and field in dict_.keys():
if dict_[field].startswith('-') and dict_[field].lstrip('-') == value:
dict_[field] = value
elif dict_[field].lstrip('-') == value:
dict_[field] = "-" + value
else:
dict_[field] = direction + value
else:
dict_[field] = direction + value
return urlencode(OrderedDict(sorted(dict_.items())))
Then you use this tag on your column header, like above:
<th>Name</th>
First time you click it will sort in 'descending' order, if you click the same header again it will revert to 'ascending' order.
This approach also preserves other parameters in your URL, like page number if you are using a paginator. It requires no extra libraries. Only thing you need to make sure is that your view is sending the RequestContext to the template.
I suggest you have a look at django-tables2. It's designed to solve your exact problem. The documentation has a bunch of examples.
continuing on the most voted answer above by Felix Kling and the addition by mpaf and ngeek, when using class based views:
do the sorting in the get_queryset(self) method, and use:
<th>Name</th>
instead of just request in your template
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have project in django rest framework that has a Store model, and I want the owner of stores to be able to enter the opening and closing hours and days that they work in their profiles of website.
What should I do?
You need to allow store owners to be able to update or partially update just their stores, so you may need to look at some sort of custom permission class - whereby you would need to allow object level permissions for editing:
permissions.py
class OwnerOrReadOnly(permissions.IsAuthenticated):
def has_object_permission(self, request, view, obj):
user = request.user
if type(obj) == type(user) and obj == user:
return True
return request.method in SAFE_METHODS
You would also then need to add the corresponding opening and closing times fields to the Store models.py class.
However, handling this may be more complex if you have opening and closing times for, for example, every day of the week, or Christmas day, or Easter etc.
You would likely need an intermediary table which tracks day, as perhaps an integer, e.g., 0 = Sunday, 1 = Monday ... etc, the "profile" field (ForeignKey relationship to a Profile instance), and the same for the store. Then, allow users to create_or_update these entries via RESTful endpoints...
There's certainly a lot to unpack...
I've followed django tutorial and arrived at tutorial05.
I tried to not show empty poll as tutorial says, so I added filter condition like this:
class IndexView(generic.ListView):
...
def get_queryset(self):
return Question.objects.filter(
pub_date__lte=timezone.now(),
choice__isnull=False
).order_by('-pub_date')[:5]
But this returned two objects which are exactly same.
I think choice__isnull=False caused the problem, but not sure.
choice__isnull causes the problem. It leads to join with choice table (to weed out questions without choices), that is something like this:
SELECT question.*
FROM question
JOIN choice
ON question.id = choice.question_id
WHERE question.pub_date < NOW()
You can inspect query attribute of QuerySet to be sure. So if you have one question with two choices, you will get that question two times. You need to use distinct() method in this case: queryset.distinct().
Just use .distinct() at the end of your ORM.
A little late to the party, but I figured it could help others looking up the same issue.
Instead of using choice__isnull=False with the filter() method, use it with exclude() instead to exclude out any questions without any choices. So your code would look something like this:
...
def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now()).exclude(choice__isnull=True).order_by('-pub_date')[:5]
By doing it this way, it will return only one instance of the question. Be sure to use choice_isnull=True though.
Because you created two objects with same properties. If you want to ensure uniqueness, you should add validation in clean and add unique index on identifier field too.
Besides filter returns all the objects that match the criteria, if you are expecting only one item to be returned, you should use get instead. get would raise exception if less or more than 1 item is found.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I want to filter queries and I want to create filters on the basis of my query string.
for example:
if request.GET.get('color'):
#filter result set on the basis of color
if request.GET.get('price'):
#filter result set on the basis of specified price
if request.GET.get('category'):
#filter result set on the basis category
How can we do this efficiently in django. I have more than 2 Million records in my database.
It can be done like this:
products = Product.objects.all()
for filter_field in ('color', 'price', 'category'):
if request.GET.get(filter_field):
products = products.filter(**{filter_field: request.GET[filter_field]})
Efficiency of that construction depends only on your database structure, on indexes that you have in DB. Cause django doesn't execute queries before return. It constructs one SQL query as result.
You can just use django's ORM like this:
if request.GET.get('category'):
category = request.GET.get('category')
filtered_result = Product.objects.filter(category=category)
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
In order to avoid changing a lot of existing code, I try to add a self foreign key to a model, then the operations(filter,get,update,save,...) on the record will automatically performed on the "real record" if it has the self foreign key value.what need I do?
class Person(models.Model):
name = models.CharField(null=True,blank=True,max_length=50)
real_one = models.ForeignKey('self',null=True,blank=True)
I am expecting:
tom = Person.objects.create(name='Tom') # id=1
Person.objects.create(name='someone', real_one=tom) # id=2
someone = Person.objects.filter(name='someone')[0]
print someone.id # 1
print someone.name # Tom
someone.name = 'Jack'
someone.save()
tom = Person.objects.filter(name='Tom')[0] # sorry, this line added late
print tom.name # 'Jack'
IMHO, you're trying to do this in a denormalized fashion and it probably isn't going to work for you. One thing you could do is:
class Person(models.Model):
name = models.CharField(null=True,blank=True,max_length=50)
real_one = models.ForeignKey('self',null=True,blank=True)
#property
def real_name(self):
if(self.real_one):
return self.real_one.real_name
else:
return self.real_name
#real_name.setter
def real_name_setter(self, val):
if(self.real_one):
self.real_one.real_name = val
self.real_one.save()
else:
self.real_name = val
self.save()
but this creates a lot of database transactions. Note also the required side effect of the setter, since it has to save the record immediately lest it lose track of which record was changed. And this still has a problem in that the following case won't work:
someone.name = 'Jack'
someone.save()
print tom.name # 'Tom' <-- The 'tom' object now has stale data!
One object is being changed, yet (as far as Python is concerned) an entirely different object is really being changed. There's no reliable way to do this without changing Django and creating a mess (Django would have to internally track every object that referred to a given record, which plays havoc with the garbage collector, Django's queryset lazy-evaluation generators, and maybe even transactions).
Your best bet is to try a different approach, or live with the fact that your example isn't going to work. If you stick with this schema, every filter and exclude queryset call, and probably others, is going to need to know about this aliasing.
IMHO, you're much, much better off changing the schema: one table with names and one table with the "real" info for each person. The name table has foreign keys to the info table.
If you're trying to do something else, then you need to explain what a lot clearer in the question.
I have a model called Question and another one called Answer.
class Question(models.Model):
text = models.CharField(max_length=140)
class Answer(models.Model):
user = models.ForeignKey(User)
question = models.ForeignKey(Question)
uncertain = models.BooleanField()
text = models.CharField(max_length=30)
Now I'd like to have a QuerySet questions which is equivalent to Question.objects.all() but including the currently logged in user's answers. I'm almost completely sure that this could be accomplished by an explicit JOIN in SQL, but I'm certain there is a better way to do this using Django's ORM.
So how would I do that?
EDIT: To clarify, I'd like to be able to loop through the QuerySet, e.g. for q in questions and then be able to see whether or not the user has answered it through something like q.answered which could be a boolean, or q.answer which could be the Answer object itself (or None).
Are you looking for something like this?
[ item.question for question in Answer.objects.filter(user=request.user) ]
Or perhaps you want to do a
questions = Question.objects.all()
for question in questions:
question.answer = question.answer_set.filter(user=request.user)
I guess I'm not understanding the question and which direction you want to go...
EDIT: Ok, based on your edit, perhaps the latter... you can see if it's an empty list or tack on a .count() and see if the value is greater than 0.
I think you're overthinking things. Essentially what you want to know (as far as I can tell - correct me if I'm wrong) is which questions have been answered by a given user, and which questions haven't (the complement). So:
user_answered_questions = set([answer.question for answer in user.answer_set.all()])
Then unanswered questions are everything else. So:
user_unanswered_questions = set(Question.objects.all()) - answered_questions
The point of doing it this way rather than uzi's solution is that you should use what you know sooner rather than later. If you filter the answer_set for every question by user, your initial query will be selecting every single answer and every single question in these tables. By starting from the known data (i.e. the user) we are selecting only answers and questions related to that user.
EDIT:
So if you then want to combine the two sets into a single list, there are a bunch of ways you could do this for instance by creating a list of tuples:
questions = [(q, q in user_answered_questions) for q in Question.objects.all()]
Then you can iterate over questions, retaining the order of the queryset:
for q in questions:
print "it is %s that this user answered the \"%s\" question" % (q[1], q[0])
It's not pretty but you get the point - you've already determined what you wanted to determine, it's just a matter of contorting it to whatever data structure you happen to need.
What is wrong with
Question.objects.filter(answer__user=current_user).select_related()