How do I structure my Django view classes? - python-3.x

I and a friend are about working on a project. I have a structure for working with my views. If I'm working with the User model, and I want to write code for CRUD operation, I write using four different classes. One for each like so:
class CreateUser(FormView):
<code here>
class ReadUser(DetailView):
<code here>
class UpdateUser(UpdateView):
<code here>
class DeleteUser(DeleteView):
<code here>
Each has a respective URL pattern:
urlpatterns = [
path("auth/users/create-user/", CreateUser().as_view(), name="create_user"),
path("auth/users/<int:pk>", ReadUser().as_view(), name="user_detail"),
path("auth/users/<int:pk>/update", UpdateUser().as_view(), name="update_user"),
path("auth/users/<int:pk>/delete/", DeleteUser().as_view(), name="delete_user")
]
He proposes that instead, all functionalities should be in one class and performed by methods, like so:
class UserView(View):
<class variables>
def post(self, request):
<code here>
def get(self, request):
<code here>
def patch(self, request):
<code here>
def delete(self, request):
<code here>
And the urlpatterns be:
urlpatterns = [
path("auth/users/", UserView.as_view(), name="user")
]
The questions I have are which is better:
Django-wise;
Generally;
When rendering from server side in django;
When writing APIs in django
The first or the second one?

I think your friend's proposal goes the right way and I would go a little bit further.
I recommend you using Django Rest Framework. It already has Class-based views that can save you a lot of time of coding.
Depending on the degree of customization you want to introduce you may choose between:
API Views or Generics Classes with Mixins
Also, I will be careful about mixing user registration and user authentication. It is quite usual to keep the resource "user(s)" and "auth" apart.
As a last advice, I will recommend you to avoid building the registration and authentication process by yourself - although it is a good learning exercise and go for an existing solution, either by public repositories or the wide variety of libraries out there that can provide you with token generation, OAUTH2, social register and authentication (Social Django f.i.) and many more.

Related

Python Login Screen Tkinter

I have been searching for an answer to this question for a couple days and all I can find is info about how to create a form for logging in. I am able to this just fine, my issue is a little more granular. I know how to capture data entered into the entry fields in tkinter with the .get() function.
I have multiple classes that serve as different parts of my program with various functions etc, but currently I have hard coded username, password, host, and database into the necessary portions of the program. This is a security risk and I would like to pass the login information to those locations allowing a user to login once and be able to enter their SQL Queries and be done, but upon closing the program/logging out these fields revert to being empty.
I have been reading about the use of setting a variable to be global, but this doesn't seem to be the best way to go about doing so since many people are saying that you should avoid globals if at all possible.
I think it should look like this:
import mysql.connector as mysql
from tkinter import *
class Login:
def__init__(self, login):
self.login=login
login.title("Login Screen")
global self.cnxn
self.cnxn=mysql.connect(
host=entry1.get(),
user=entry2.get(),
passwd=entry3.get(),
database=entry4.get())
self.entry1=Entry(login)
self.entry2=Entry(login)
self.entry3=Entry(login)
self.entry4=Entry(login)
self.entry1.pack()
self.entry2.pack()
self.entry3.pack()
self.entry4.pack()
class Other:
def__init__(self, other):
self.login=other
other.title("Login Screen")
def add():
c=self.cnxn
c.cursor()
self.cnxn.commit()
self.cnxn.close()
main=Tk()
Login(main)
main.mainloop()
My understanding of using globals is very limited, but I believe I would be able to pass the global variable to other classes and functions.
Is there a better way to do what I am trying to do?
If you wish to define a global variable for a specific class you can simply add the variable above the class initialiser as follows...
class myClass:
my_global_var = "Hi"
def __init__(self):
print(myClass.my_global_var)
myClass()
You can acccess the variables using this format classname.globalvariable you can now access this variable anywhere in your program.

Pyramid routing to class methods

From the pyramid documentation, there exists an attr argument on configurator's add_view that states:
The attr value allows you to vary the method attribute used
to obtain the response. For example, if your view was a
class, and the class has a method named index and you
wanted to use this method instead of the class' __call__
method to return the response, you'd say attr="index" in the
view configuration for the view.
With this in mind, I'd like to route all requests under /myrequest to the class MyRequest. Given the following class:
#view_defaults(renderer='json')
class MyHandler(object):
def __init__(self, request):
self.request = request
def start(self):
return {'success': True}
def end(self):
return {'success': True}
It would seem the way to do this would be in the configuration, add these lines:
config.add_view(MyHandler, '/myrequest', attr='start')
config.add_view(MyHandler, '/myrequest', attr='end')
and so on, for all the methods I want routed under MyHandler. Unfortunately this doesn't work. The correct way to do this appears to be:
config.add_route('myroutestart', '/myroute/start')
config.add_route('myrouteend', '/myroute/end')
config.add_view(MyHandler, attr='start', route_name='myroutestart')
config.add_view(MyHandler, attr='end', route_name='myrouteend')
This seems like an awful lot of boilerplate. Is there a way to bring this down to 1 line per route? Or more ideally, 1 line per class?
Example #4 in the Route and View Examples from The Pyramid Community Cookbook v0.2, Pyramid for Pylons Users, offers the following.
# Pyramid
config.add_route("help", "/help/{action}")
#view_config(route_name="help", match_param="action=help", ...)
def help(self): # In some arbitrary class.
...
Although this cookbook recipe mentions pyramid_handlers as one option to do this, the article "Outgrowing Pyramid Handlers" by one of the maintainers of Pyramid encourages the use of Pyramid's configuration.

Dynamically generate Flask-RESTPlus routes

I am trying to abstract away some of the route class logic (i.e. I am looking to dynamically generate routes). api.add_resource seemed like the right place to do this.
So this is what I am trying to do:
# app.py
from flask import Flask
from flask_restplus import Api, Resource, fields
from mylib import MyPost
# Define my model
json_model = api.schema_model(...)
api.add_resource(
MyPost,
'/acme',
resource_class_kwargs={"json_model": json_model}
)
And then in mylib:
# mylib.py
def validate_endpoint(f):
def wrapper(*args, **kwargs):
return api.expect(json_fprint)(f(*args, **kwargs))
return wrapper
class MyPost(Resource):
def __init__(self, *args, **kwargs):
# Passed in via api.add_resource
self.api = args[0]
self.json_model = kwargs['json_model']
# I can't do this because I don't have access to 'api' here...
# #api.expect(json_model)
# So I am trying to make this work
#validate_endpoint
def post(self):
return {"data":'some data'}, 200
I don’t have access to the global api object here so I can’t call #api.expect(json_model). But I do have access to api and json_model inside of the post method. Which is why I am trying to create my own validate_endpoint decorator.
This does not work though. Is what I am trying to do here even possible? Is there a better approach I should be taking?
Stop using flask-restplus. Thats the most valuable answer I can give you (and anyone else).
Ownership is not there
Flask-restplus is a fork of flask-restful. Some engineers started developing features that suited them. The core guy has ghosted the project so its been officially forked again as Flask-Restx.
Poorly designed
I used to love flask when I was a yout’. I’ve realized since then that having global request, application, config that all magically update is not a good design. Their application factory pattern (to which flask-restplus conforms) is a style of statefully mutating the application object. First of all, Its hard to test. Second of all, it means that flask-restplus is wrapping the app and therefore all of the requests/handlers. How can anyone thing thats a good thing? A library whose main feature is endpoint documentation has its filthy hands all over every one of my requests?? (btw, this is whats leading to your problem above) Because my post is serious and thoughtful I’m skipping my thoughts on the Resource class pattern as it would probably push me into the waters of ranting.
Random Feature Set
A good library has a single purpose and it does that single thing well. Flask-restplus does 15 things (masking, swagger generation, postman generation, marshaling, request arg validation). Some features you can’t even tell are in the libraries code by reading the docs.
My solution to your problem
If you want to document your code via function decorators and models use a tool that does that alone and does it well. Use one that won’t touch your handlers or effect your actual request decorators. Use oapispec for swagger generation. For the other features of flask-restplus you’ve got marshmallow for marshaling request/response data, pydantic for validating request objects and args, and so on.
btw, I know all this because I had to build an api with it. After weeks of fighting the framework I forked it, ripped it apart, created oapispec, and trashed it from the project.

python tornado how to get id of a edge

I have a web application that runs on flask web framework. Flask couldn't answer application requirements anymore. So we have decided to migrate tornado.
I need to handle below two request.
/entry GET Method
/entry/id GET Method
When first request called it must return authenticated entry.
When second request called it must return the entry whose entry_id
is id
Is there a different nice solution to handle above request except my solution. The solution i have found it creates cyclomatic complexity.
def get(self):
id = self.request.path.split('/')[-1]
if id is None:
#return authenticated user
else:
#return the user whose entry_id is id
Note: I am looking a solution like this:
#rest_user.route('/user', methods=['GET'])
#some code
#rest_user.route('/user/<user_id>', methods=['GET'])
#some code
The analogous arrangement in Tornado uses two handler classes (perhaps with a common base class for shared methods):
class AuthedUserHandler(RequestHandler):
def get(self):
...
class UserHandler(RequestHandler):
def get(self, user_id):
...
app = Application([
('/user', AuthedUserHandler),
('/user/(.*)', UserHandler),
])

django-rest-framework: independent GET and PUT in same URL but different generics view

I'm using django-rest-framework and I need to map in the URL file two generic views with the same url (iḿ already using URLs but not Routes):
I need to allow GET, PUT and DELETE verbs in just one url (like /api/places/222) and allow everyone to get every field with the related Entity Place but just allow to update (PUT) one field using the same url.
Place Entity:
- id (not required in PUT)
- name (required always)
- date (not required in PUT but required in POST)
URL
url(r'^api/places/(?P<pk>\d+)/?$', PlacesDetail.as_view(), name='places-detail'),
I tried to use RetrieveDestroyAPIView and UpdateAPIView, but I'm unable to use just one URL.
I suggest you to create a few serializers that satisfy your needs.
Then override the get_serializer method of your view so that the view switches serializers according to an HTTP request method.
This is a quick untested example:
class PlacesDetail(RetrieveUpdateDestroyAPIView):
def get_serializer_class(self):
if self.request.method == 'POST':
serializer_class = FirstSerializer
elif self.request.method == 'PUT':
serializer_class = SecondSerializer
return serializer_class
...
Look at the base class method's comment:
def get_serializer_class(self):
"""
Return the class to use for the serializer.
Defaults to using `self.serializer_class`.
You may want to override this if you need to provide different
serializations depending on the incoming request.
(Eg. admins get full serialization, others get basic serialization)
"""
...

Resources