cascading forms in Django/else using any Pythonic framework - python

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.

Related

Best Practice: Processing complex dynamic form on single-page with Django

I'm looking for the most pythonic way to handle a complex form on a single-page. My "submit" page has a series of questions that, based on the user's input, will generate different forms/fields.
A simplified example:
--- Shift 1 --> Form #1
--- Yes -- What shift? -- |
| --- Shift 2 --> Form #2
|
Enter Date --- Did you work? ---|
|
| --- Yes --> Form #3
--- No -- Was this PTO? ---|
--- No --> Form #4
I'm trying to figure out most efficient/pythonic way to handle the above.
Possible Approaches:
Lots of jquery, ajax, and function based views. This is my current setup, but I'd like to move it to CBV and ModelForms if possible because my current code is about 2000 lines (with 10+ ajax functions, 10+ view-handling urls, and too many input fields to count) within my template/models/views just to load/process this form. It is a complete nightmare to maintain.
Single page with ModelForms embedded within a dynamic div. The form page calls a jquery load depending on your answers to the questions. For instance, if you answered "Today", "Yes", "Shift 1", I would call $("#form-embed").load("/forms/form1/") which contains the Form #1 ModelForm. A couple problems with this: 1. Some of the "questions" are actually form fields, and if I'm reloading a blank form, then that field would be blank. I could solve this with JS on the front-end or custom cleaning on the back-end, but this ends up being a lot of code as well. And 2. Form POSTing and error handling would be pretty complex with so many potential forms on one page.
Same as above but with an Iframe. This solves some of the above issues, but feels "icky" for some reason and makes me worry about responsive UI/compatibility across platforms.
Multiple pages, each with its own form. This eliminates the convenience of a single-page approach, which I'd really like to keep if possible.
Combine all my models into a single model. This gets pretty complex pretty quickly because the actual fields involved on each form are very different, and the logic handling would therefore get messy and bloated.
Create a new single model with a corresponding modelform for use only with this form that contains all possible fields, dynamically displayed via JS based on user input, then routes the fields to the appropriate models after submission.
Don't use modelforms, instead create my own custom Form Class that involves all possible fields, then route to the appropriate models after submission. Use JS to display/hide fields based on user input.
Is there an approach I'm missing, or is one of these the best? These would all theoretically work just fine, but none of them feels very pythonic. #7 maybe feels like the best option, but I'm still not super happy with it.
My hope for the front-end is to maximize ModelForm and Django's template management, while minimizing JS. My hope for the back-end is to maximize CBV/ModelForm customization while minimizing FBV. My overall goal is to reduce code volume and improve maintainability/modification.
Looks like the functionality I was looking for is the class-based view FormView and forms.Form (not forms.ModelFormView).
In forms.py, I created a forms.Form form which contained all possible fields (ended up being about 10, able to reuse several. Had to make a lot of them required=False), then loaded them all at the same time in individual divs within a FormView. Each div shared the name of the field, so I could easily hide/show each div using simple JS depending on what combination of fields I wanted to display based on user input.
I also included a hidden "form number" field which updates based on the final input, which helps to direct my form validation.
I then used the def clean(self) mixin in my forms.py to process each individual form.
Haven't finished the entire thing yet, but it's already looking like my code length will be cut from 2000+ down to a couple hundred or so. Plus this will be much easier to maintain, and keeps most of my logic on the serverside rather than in the html file.

In Python Flask WTForms, how to create a dependency over another field

I've a source field:
source = SelectField("Source", choices=[
('option1', 'option1'),
('option2', 'option2'),
('option3', 'option3'),
validators=[InputRequired()])
Then an uri field which requires a different regex based on the above:
uri = StringField('URI', Regexp(regex=r'regex1'))
Eg. if option1 is selected regex will be regex1, if option2 regex2, and so on.
What would be the proper way to implement it with WTForms?
This functionality doesn't exist in WTForms. You'll have to tool this yourself. This quickly gets nontrivial, depending on your specific application logic/needs.
One way would be to have client-side JS send requests to a view that dynamically generates a new form, adding on the subsequent sections of the form based on inputs. For example, your fields could have an onChange or onBlur function that sends the inputs to a view that returns a new form with the next set of fields added on.
Another way to go about this would be with some clever form rendering, CSS and JS. For example, the form would be rendered with all possible fields, but the fields will be hidden and revealed conditionally based on previous selections through via JS/CSS. One concern with this method is that validation becomes complicated.
There are a few writeups out there on how this is accomplished with Django Forms, but not WTForms. Though, the same concepts should be readily applicable to WTForms.
Related docs: dynamic form composition.

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.

Django - Managing page content in Django Admin

I'm new to working with Django and am developing for a client who wants to be able to change page content in the Django Admin. They need to be able to change the html of the index page without editing the files on the server.
I know about flatfiles but I'm not sure that's completely what I'm after as I can't display stuff such as Django forms for example.
EDIT: Kind of like how a CMS works but without the users/group stuff and be able to use Django View modules such as forms.
Any advice?
Thanks
Honestly, the scope of what you're looking for is too huge to cover in this format. There's a number of ways this could be done, but they're all going to require some work and customization based on the client's needs.
Flatpages could work if you allow HTML content and make sure the content is rendered as "safe" in the template. This really only covers the "content" area of the site, though. It wouldn't be wise to use flatpages for an entire site template, including header, sidebar, footer, etc.
You could create editable areas. So, you actually create models for things like headers, sidebars, footers, and modules within those areas, and then just pull them into the template as needed. Then, the client is only editing pieces of the template instead of responsible for the whole HTML document.
Forms are going to be a challenge, because they require backend-processing that requires a connected view. The client won't be able to just arbitrarily drop in some form code and have a form. But, you could use a third-party service form forms and just embed them in the available content regions. Or, there's a couple of django apps that try to implement a type of "form builder" in the admin. That might somehow let the client add a form via something like the shortcodes used in Wordpress, but you'd likely have to lay down some infrastructure to make that work.
At a certain point, stuff like this reaches a point of diminishing returns, though. The only way to allow total customization of the template is to drop down into the actual physical file and make changes there. You can make certain things easier for the client, but ultimately, they either need to scale back their customization needs or deal with the fact that they'll have to work with the filesystem.
I don't believe that is possible at this time. Of course you can edit your models but templates, I think not.
I would find out how much they need to change? If they plan a complete redesign every week then you're still looking for an answer. If they just need a dynamic front page then you can split it up into variables and let them edit sections of html. Much safer and less prone to breaking the html.

Categories