create view similar to another one - python

I have to make some changes in a django project and though I'm familiar with python, I'm not with django.
This is my situation:
I have a table with the field "active". What I need to do is to let the users to sort the table based on the value of the field (yes/no).
I looked into views.py and I realized that there is a view that sorts the table based on the id:
users = User.objects.all().order_by('id')
My questions are:
How can I make the view to sort the table based on the url parameter?
Do I have to create another view or can I use the same with some kind of modifications?

You can use the same view.
def myView(request):
get_param = request.GET.get('my_param', 'id')
#some more processing
users = User.objects.order_by(get_param) #note - you dont need the `all()`
#rest of the code here.

That depends on what you want to render in your template. If both views will render similar html the it's probably better refactor them in a generic view and do the sorting depending on GET parameters.
I like separation of concerns, so another approach may be refactoring the view code inside a helper function and just call it inside each view with separated urls.
If the views doesn't render similar html and are different from each other in every aspect except that they sort something in some place, then I think the best way is to code both view separately.
It's just a consideration problem but answering your question you can get GET params accessing the request.GET or request.POST depending on the method.
Hope it helps!

Related

Django Custom Template tag to check model's field

I have a model that will be displayed in a ListView. One of the fields in the model is category which has 3 choices. When I display the template, I want to be able to tell between the 3 categories. I considered overriding get_context_data() to add a context for each category by getting all the objects and filtering them.
Would that be a better approach than a custom template tag?
And even if it is, assuming I still want to create the custom template tag to accomplish this, how would I write it? I know how to write custom tags, but I am unsure how to write one such as this.
Only idea I can come up with is to create a tag something like:
#register.simple_tag(name="is_cat1", takes_context=True)
def is_cat1(self, context):
objs = context['object_list']
if (MyModel.objects.filter(category__icontains="Cat1") in objs):
objs = MyModel.objects.filter(category__icontains="Cat1")
return objs
Could anyone provide an example of such a filter that deals with models like this? As well as answer my question as to whether it would be better to use context?
Thanks
Using AJAX is the correct solution. Such an operation doesn't fit with Django's framework and intended use.

Django Rest Framework Pagination Since ID

I have built an API with Django Rest Framework. I want to change pagination for a better user experience.
The problem:
The client makes a call to request all posts. The request looks like:
http://website.com/api/v1/posts/?page=1
This returns the first page of posts. However, new posts are always being created. So when the user requests:
http://website.com/api/v1/posts/?page=2
The posts are almost always the same as page 1 (since new data is always coming in and we are ordering by -created).
Possible Solution?
I had the idea of sending an object id along with the request so that when we grab the posts. We grab them with respect to the last query.
http://website.com/api/v1/posts/?page=2&post_id=12345
And when we paginate we filter where post_id < 12345
But this only works assuming our post_id is an integer.
Right now I'm currently only using a basic ListAPIView
class PostList(generics.ListAPIView):
"""
API endpoint that allows posts to be viewed
"""
serializer_class = serializers.PostSerializer # just a basic serializer
model = Post
Is there a better way of paginating? so that the next request for that user's session doesn't look like the first when new data is being created.
You're looking for CursorPagination, from the DRF docs:
Cursor Pagination provides the following benefits:
Provides a consistent pagination view. When used properly CursorPagination ensures that the client will never see the same item twice when paging through records, even when new items are being inserted by other clients during the pagination process.
Supports usage with very large datasets. With extremely large datasets pagination using offset-based pagination styles may become inefficient or unusable. Cursor based pagination schemes instead have fixed-time properties, and do not slow down as the dataset size increases.
You can also use -created as the ordering field as you mentioned above.
How about caching the queryset? So that the next page is served from the same query set, and not from a new one. And then you could use a parameter to get a new queryset when you want.
Something like this:
from django.core.cache import cache
class PostList(generics.ListAPIView):
def get_queryset(self):
qs_key = str(self.request.user.id) + '_key'
if 'refresh' in self.request.QUERY_PARAMS:
# get a new query set
qs = Post.objects.all()
cache.set(qs_key, qs)
return cache.get(qs_key)
So basically, only when your url will be like this:
http://website.com/api/v1/posts/?refersh=whatever
the request will return new data.
UPDATE
In order to provide each user with it's own set of posts, the cache key must contain an unique identifier (which might be the user's ID):
I also updated the code.
The downside to this approach is that for a very large number of users and a large number of posts for each user, it might not work very well.
So, here is my second idea
Use a TimeStamped model for the Post model, and filter the query set based on the created field.
I don't know much about your models and how exactly they are built, so I guess you will have to choose which solution is best for your app :)
Maybe you can add a field to every object like "created_at/updated_at". Then you can save the timestamp when the user made the request and filter out everything that came after it.
Haven't tried it myself but I guess it might work on your case

How can I share a selected amount of data with all my templates in pyramid?

I read the cookbook article on making user objects avail to all requests but I may not understand it fully because I can't see if it is related to my problem.
I render quite a few templates on a site I'm working on and there's different user info each templates needs. For example, like this page on SO my every page needs to display my username, points, number of notifications, number of badges, etc. I have all this information but I find myself having to add it to each request dictionary I send to the template like so:
return dict(page=page, name=name, save_url=save_url,
logged_in=authenticated_userid(request), title='add new', url='/new', points=points, num_badges=badges)
Is there a way to combine all this once so I can just send one entry to each view? I'm sure its not good to run the same query every time but its also annoying to have to type it for every view. Any suggestions?
The simplest method would be to generate your 'common' information in one method, returning a dict, then updating your local view dict with that information
local = dict(page=page, name=name, save_url=save_url, title='add new',
url='/new', points=points, num_badges=badges)
local.update(retrieve_common_information(request))
return local
Another method is to use something like the pyramid_viewgroup (documentation now located at a new location), where you delegate the rendering of common 'snippets' of your pages to separate views.
One such view could take care of the common user information you want to render, and be reused everywhere.

Return template as string - Django

I'm still not sure this is the correct way to go about this, maybe not, but I'll ask anyway. I'd like to re-write wordpress (justification: because I can) albeit more simply myself in Django and I'm looking to be able to configure elements in different ways on the page. So for example I might have:
Blog models
A site update message model
A latest comments model.
Now, for each page on the site I want the user to be able to choose the order of and any items that go on it. In my thought process, this would work something like:
class Page(models.Model)
Slug = models.CharField(max_length=100)
class PageItem(models.Model)
Page = models.ForeignKey(Page)
ItemType = models.CharField(max_length=100) # tells me which model to display
InstanceNum = models.IntegerField() # tells me which instance of which model...
Then, ideally, my template would loop through all the PageItems in a page which is easy enough to do.
But what if my page item is a site update as opposed to a blog post? Basically, I am thinking I'd like to pull different item types back in different orders and display them using the appropriate templates. Now, I thought one way to do this would be to, in views.py, to loop through all of the objects and call the appropriate view function, return a bit of html as a string and then pipe that into the resultant template.
My question is - is this the best way to go about doing things? If so, how do I do it? If not, which way should I be going? I'm pretty new to Django so I'm still learning what it can and can't do, so please bear with me. I've checked SO for dupes and don't think this has been asked before...
I've also looked at Django-cms to see if that helps, but I couldn't get to grips with it.
Any suggestions?
First, some puzzelement.
InstanceNum = models.IntegerField() # all models have primary keys.
In Django, all model are assigned an integer primary key.
The comment doesn't make sense, since you don't need to add a primary key like this. The PageItem already has a primary key.
Also, please use lower case letters for attributes. Only Use Upper Case for Class Names. Please.
"But what if my page item is a site update as opposed to a blog post? Basically, I am thinking I'd like to
pull different item types back in
different orders and display them
using the appropriate templates"
Different types usually means different models. Rather than a vague "PageItem", you probably want to have "Site Update" and "Blog Post" as separate models.
You can then iterate through these various objects and display them in the template.
You can easily have your various Models defined with a method to return HTML information. You don't (generally) want to return fully-baked HTML. But CSS ID or Class information is sometimes helpful.
class SiteUpdate( models.Model ):
page = models.ForeignKey(Page)
item_text = models.CharField(max_length=100)
item_css_class = models.CharField(max_length=64)
Now you can generate this into the template with a simple <div class="{{item.item_css_class}}">{{item.item_text}}</div> and use CSS to handle the formatting details that distinguish site update as opposed to a blog post.
The include template tag can take a variable containing the template to include, so you could loop through a sequence containing the various sub-templates and include them in turn, maybe using a dict to map friendly names to template filenames.

cascading forms in Django/else using any Pythonic framework

Can anyone point to an example written in Python (django preferred) with ajax for cascading forms? Cascading Forms is basically forms whose field values change if and when another field value changes. Example Choose Country, and then States will change...
This is (mostly) front-end stuff.
As you may have noticed Django attempts to leave all the AJAX stuff up to you, so I don't think you'll find anything built in to do this.
However, using JS (which is what you'll have to do in order to do this without submitting a billion forms manually), you could easily have a django-base view your JS could communicate with:
def get_states(request, country):
# work out which states are available
#import simplesjon as sj
return sj....
Then bind your AJAX request to the onchange event of the select (I can't remember if that's right for select boxes) and populate the next field based on the return of the JSON query.
10 minute job with jquery and simplejson.
I would also suggest considering getting a mapping of all data once instead of requesting subfield values one by one. Unless the subfield choices change frequently (states/cities change?) or huge in numbers (>1000) this should offer best performance and it is less complex.
You don't even need to create a seperate view, just include a chunk of JavaScript (a JSON mapping more precisely) with your response containing the form.

Categories