I'm using django rest framework and trying to save some data so it will be accessible by GET, PUT, DELETE.
So when user send GET request server send some information (a random number, for example) and that information is needed after user sends PUT request on the same url. How would one save such information? I'm using class-based views.
So i want to save that information on GET method.
I tried saving that information to class variable self.information, but the problem is self.information is empty when PUT method is getting called.
I also tried saving it to session, but like class variable, session is also empty when PUT method is being executed.
class SampleClass(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, generics.GenericAPIView):
serializer_class = SampleSerializer
def get(self, request):
random_number = random.randint(0, 10)
request.session['number'] = random_number;
content = {'random_number': random_number}
return Response(content)
def put(self, request):
number = request.session['number'] # key doesn't exists
process_number(number)
# ...
Before I begin, it's important to note that HTTP is a stateless protocol, and you are looking to add state into the mix. If you can rework what you are doing to not depend on previous requests, that will probably be better in the long run.
I tried saving that information to class variable self.information, but the problem is self.information is empty when PUT method is getting called.
This is because the class is re-initialized for each request. Because of that, the class variables don't persist across requests. Even if they did, that would mean everyone would get access to the persisted value, and it isn't made clear if that is what you are looking for.
I also tried saving it to session, but like class variable, session is also empty when PUT method is being executed
This doesn't work because Django sessions are persisted through the use of cookies. While this might work for SessionAuthentication, it won't work for any authentication that happens outside of the browser. This is because the session cookies won't be included, so Django will think the new requests are under a different session.
Now, just because HTTP is mostly stateless and doing this might lead to future trouble, that doesn't mean that you should never do it. The Django sessions wouldn't exist if there wasn't a need for it, and there are ways to save state without Django sessions.
Create a new model for the state - This is usually the best way to save state per-user and ensure that it doesn't fade away. The model needs a user field along with the fields that the state will be stored in, and all you need to do is have a query that retrieves the state object for the user.
Use the Django cache - This is the way I would recommend it for the case that you specified in your question. When you don't need to store much state, the state is shared among everyone, or you can live with it not existing (expiring), storing the data in a simple cache environment will probably work the best. You have much more control over what is stored, but at the expense of having to do more work.
Related
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.
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
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
I'm trying to use Tornado with SqlAlchemy, I need to pass the current user from RequestHandler (tornado) to models (SqlAlchemy) in the insert or update action. But I don't want to pass the value directly to the model, example:
#### RequestHandler POST method...
user = Session.query(User).get(1)
user.name = "bla, bla, bla..."
user.updated_by = self.current_user # don't use...
session.commit()
I'm using a global variable, in a __ init__.py file, and set the current user value in the RequestHandler and after, get the value, in before update event with SqlAlchemy.
The idea is to know what user is the creator and updater.
Why I don't want pass the current user directly to model like the before example ?, because this will be a tool for other developers, and I'm trying to make comfortable for them, also, they can forget about it and it is important.
Is this a good idea, or maybe is there other better way ?
Your solution will have issues if you're handling more than one request at a time. Tornado is an async web framework so another request might overwrite your global var and set the user to someone else. It's good practice to store request depending data on self, tornado will make sure that data is altered by other simultaneous requests.
A solution that might work for you is to add your tool in the basic handler or create a decorator. It's tricky to sugest more details, please include more info in your question if you would like to get better alternatives.
The current user is available in every handler (and template). How you determine, authenticate and set the current user is up to you.
Basically just subclass tornado.web.RequestHandlerand override the get_current_user method in your new/own BaseHandler.
Here the quote from the tornado docs:
tornado User authentication
User authentication
The currently authenticated user is available in every request handler as self.current_user, and in every template as current_user. By default, current_user is None.
To implement user authentication in your application, you need to override the get_current_user() method in your request handlers to determine the current user based on, e.g., the value of a cookie. Here is an example that lets users log into the application simply by specifying a nickname, which is then saved in a cookie.
You can see a fully working example in the official tornado blog demo
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.