Exporting queryset data using Django without have to re-query data - python

I have set up a Django app that queries from a PostgreSQL database. Exporting all the data within a model seems relatively straight forward but what if I wanted to export only the data from a returned queryset.
Currently I'm managing this by having a button on my page and changing the url when the user wishes to export data. The code within the view that I'm rendering is as follows.
def export_data(request,pk):
resource_class = MDPResource()
queryset = MDP.objects.filter(mdp_id=pk)
dataset = person_resource.export(queryset)
response = HttpResponse(dataset.csv, content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="mdpbasic.csv"'
return response
However, this means that I'm going to be making one query when the user initially opens the page and then a second query (in effect 2 extra) when the user wishes to export the data which I have already queried for in the previous view.
Moreover, in a section of my page I'm also using Q models for complex filtering. The above method is not sufficient for exporting data in that case (I don't want to have to reconstruct the query).
I also do not want to have to write the data to a file (if I can help it) because then that raises the issue of having to delete it using os once the user has exported their data.
Generating CSV file with Django (dynamic content)
I have already checked out this question but I'm not sure how passing a dictionary to a urlpattern works and it still seems as though the query is being made one more time anyways (still one less than my current method).
I don't know if I should be checking out apps for this particular purpose. I've looked into a couple such as django-queryset-csv and django-import-export but none of them seem to do what I've mentioned.
django: export current queryset to csv by button click in browser
I've seen this example that makes use of class-based views but I wanted to see if there was a way to do it with function-based views so I don't have to migrate all my views to class-based ones.

Related

Handling input from an input field or form field with Django

So I'm trying to learn Django by building a very simple single-page site that just takes emails for subscriptions and stores it into djangos backend. I made an html page for the site that has form and input elements, and I've successfully rendered the page by following the documentation. I even built a model called 'subscriptions', to take email strings, but now i'm unsure about how to handle the input from the html page and store the emails in the backend.
All the documentation is kind of confusing cause it instructs me to build a separate .html file for the form, and handle it in another views and model page, which just seems unnecessary.
Does django necessitate handling input in a separate forms.html file? Or can i just use the index.html, and add views to 'views.py' or revise 'models.py'?
I'm pretty confused, all help and examples are very appreciated!
Django documentation on Working with forms mentions a lot of examples around what you want to do.
Create a forms.py as mentioned on the page and you can create an equivalent view for it in views.py which recieves form values.
Once you have your form data in the view as shown in example, you can save it to using, as something like:
s = Subscriptions(email=email)
p.save()
Refer more on models here.

Convert Django Views to rest services

I have an application created long back, now client want to expose its some of views as APIs without breaking existing functionality, so that they can directly consume APIs using REST Tools to see the reports.
Is there any easier way, I can convert my function to a REST View.
P.S - I kept code shorter here to keep question simple, but in fact, its much complex in the actual app.
eg.
URL : -
`path('/users', views.show_user_details, name='users'),`
VIEW
def show_user_details(request, user_id):
users = User.objects.all()
return render(request, "Users.html", {"users":users})
In REST Views, I want it to convert its input and output so that it can be accessible with same urls(or with little modifications), without much updating the existing views.
`path('rest/users', views.show_user_details, name='users'),` #-- I am ok to add new url like this, but without much change in existing view .
def show_user_details(request, user_id):
users = User.objects.all()
return JsonResponse({"users":users})
Due to the fact that a normal website visit is still a GET request and GET is just one of your usual REST actions, you'll probably want to prepare your own independent API endpoint. Check out django-rest-framework for that, and you might just feel at home for this task.

Is there pyramid package for storing form related information serverside (avoid mirroring hidden fields)?

Background: I'm currently creating a project in pyramid. It uses beaker sessions and SQLAlchemy as DB-backend.
Some forms contain information in hidden fields, with the only purpose of supplying it to the view that processes the post, the user never sees them and doesn't need to. An example:
A DB-entity can be edited by the user. Since all data fields of the entity, including the name, can be edited, the ID of the entity is put in a hidden field, so the view can query the object and update it. This approach has some flaws:
The ID of my entities is no concern of my users. They should not even be aware of it.
Data being resubmitted by the client can be tinkered with. Someone might try to get access to other entities by forging a different id here.
In other scenarios there could be more mirrored data than just an id (maybe the return to url? Maybe much more somewhere). Using hidden fields for that would transmit the data to the client and back, needlessly (bandwidth) and makes it necessary to validate it.
Transmitting data over insecure channels (the client) without need is just wrong. The solution is not that complicated: store that information on the server (in session or DB), and make it accessible with a key (form-id?), similar to a session, with a session-id. Put that totally anonymous token into a hidden field. That will be the only hidden field needed in the form. Everything else would be stored on the server and be restored from the view responding to the post-request (well - I would still have my CSRF-token in there, because it's in all my post requests). This would also make it easy, to give forms a timeout, since you can make the form-id expire after some hours or so.
If I recall correctly, drupals does supply like this by default. I would not really expect pyramid itself to have support for this, but would imagine there must be a package doing this, using the pyramid supplied session object, still could not find any. I'm sure I could write something usable myself, but why do so if there might be something awesome out there already?
Anyone knows of such packages?
If I understand you, you want to update a model without using hidden fields on forms.
Here is how to do it
Using pyramid_simpleform and Urldispatch
#view_config(route_name="my_route",renderer="myrenderer.mako")
def update(request):
id = request.matchdict['id']
#assuming you have an SQLalchemy model called MyModel which you imported
#your model has a method that gets by id
toupdate = MyModel.get_by_id(id)
form = Form(request, schema=MyModelSchema,obj=toupdate)
if not toupdate:
#you can flash a message here and redirect wherever you want
return HTTPFound(location=request.route_url('home'))
if 'submit' in request.POST and form.validate():
form.bind(toupdate)
DBSession.add(toupdate)
DBSession.flush()
#redirect
return HTTPFound(location=request.route_url('home'))
return dict(form=FormRenderer(form))
At the view, just draw your form fields without any hidden field using the form object.
#configure your route as below
config.add_route('my_route','/myroute/{id}/edit')
UPDATE
to use webhelpers tool. Follow as bellow(Using Mako template)
<%
from webhelpers.html.tools import js_obfuscate
%>
js_obfuscate("<input type='hidden' name='check' value='valid' />")
to obfuscate the data in javascript tag

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

Difference between Model and Form validation

I'm currently working on a model that has been already built and i need to add some validation managment. (accessing to two fields and checking data, nothing too dramatic)
I was wondering about the exact difference between models and forms at a validation point of view and if i would be able to just make a clean method raising errors as in a formview in a model view ?
for extra knowledge, why are thoses two things separated ?
And finnaly, what would you do ? There are already some methods written for the model and i don't know yet if i would rewrite it to morph it into a form and simply add the clean() method + i don't exactly know how they work.
Oh, and everything is in the admin interface, havn't yet worked a lot on it since i started django not so long ago.
Thanks in advance,
You should use model (field) validation to make sure the returning datatype meets your database's requirements. Usually you won't need this because django's builtin fields do this for you, so unless you've built some custom field or know what you are doing you shouldn't change things.
Form validation is where you clean the user's input, you can add a clean method for every form field by adding a clean_FIELD(self) method, e.g.
class ContactForm(forms.Form):
# Everything as before.
...
def clean_recipients(self):
data = self.cleaned_data['recipients']
if "fred#example.com" not in data:
raise forms.ValidationError("You have forgotten about Fred!")
# Always return the cleaned data, whether you have changed it or
# not.
return data
Before a Form's main clean method is ran, it checks for a field level clean for each of its fields
Generally models represent business entities which may be stored in some persistent storage (usually relational DB). Forms are used to render HTML forms which may retreive data from users.
Django supports creating forms on the basis of models (using ModelForm class). Forms may be used to fetch data which should be saved in persistent storage, but that's not only the case - one may use forms just to get data to be searched in persistent storage or passed to external service, feed some application counters, test web browser engines, render some text on the basis of data entered by user (e.g. "Hello USERNAME"), login user etc.
Calling save() on model instance should guarantee that data will be saved in persistent storage if and only data is valid - that will provide consistent mechanism of validation of data before saving to persistent storage, regardless whether business entity is to be saved after user clicks "Save me" button on web page or in django interactive shell user will execute save() method of model instance.

Categories