Flask. Processing a form on another page. TypeError: The view function did not return a valid response - python-3.x

Good day!
I'm new to Python and Flask
I am trying to render a form on another page when I apply this construction :
#app.route('/tools', methods=['POST', 'GET'])
def tools():
"""Form Create Users"""
createadduser_form = ToolsAddUser()
return render_template("tools.html", title='Admin Tools', **locals())
#app.route('/createuser', methods=["GET", "POST"])
def createuser():
if request.method == 'POST':
adduser_clientid = request.form["adduser_clientid"]
adduser_value = request.form["adduser_value"]
create(adduser_clientid, adduser_value)
return redirect("tools")
But in the event that I use another one with field validation, it does not work:
#app.route('/tools', methods=['POST', 'GET'])
def tools():
createadduser_form = ToolsAddUser()
return render_template("tools.html", title='Admin Tools', **locals())
#app.route('/createuser', methods=["GET", "POST"])
def createuser():
createadduser_form = ToolsAddUser()
if createadduser_form.validate_on_submit():
adduser_clientid = request.form["adduser_clientid"]
adduser_value = request.form["adduser_value"]
create(adduser_clientid, adduser_value)
return redirect("tools")
I understand the problem here:
if createadduser_form.validate_on_submit():
if request.method == 'POST':
In the first option, when you click on the button, the script works as needed (the script is launched powershell, so do not pay attention to the names of the variables, this is a test)))) everything works well
In the second option, it shows an error:
I can't understand what the problem is, little experience. I would be very grateful for your help.
http://127.0.0.1:5000/createuser
TypeError
TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.
Traceback (most recent call last)
File "E:\Project\web\venv\lib\site-packages\flask\app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "E:\Project\web\venv\lib\site-packages\flask\app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "E:\Project\web\venv\lib\site-packages\flask\app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "E:\Project\web\venv\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "E:\Project\web\venv\lib\site-packages\flask\app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "E:\Project\web\venv\lib\site-packages\flask\app.py", line 1953, in full_dispatch_request
return self.finalize_request(rv)
File "E:\Project\web\venv\lib\site-packages\flask\app.py", line 1968, in finalize_request
response = self.make_response(rv)
File "E:\Project\web\venv\lib\site-packages\flask\app.py", line 2098, in make_response
"The view function did not return a valid response. The"
TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.
Below, just in case, the form itself...
class ToolsAddUser(FlaskForm):
adduser_clientid = StringField('Client ID',
validators=[DataRequired()],
render_kw={'class': 'form-control',
'placeholder': 'Client ID'})
adduser_value = StringField('Value',
validators=[DataRequired()],
render_kw={'class': 'form-control',
'placeholder': 'Value'})
submitbuttonuser = SubmitField('Submit',
render_kw={'class': 'btn btn-dark'})
I apologize for the inaccuracies in the wording
<form action="/createuser" method="post">
 <div class="form-group form shadow">
 <label for="">
 <h5>Add User</h5>
 </label>
 {{ createadduser_form.adduser_clientid }}<br>
 {{ createadduser_form.adduser_value }}<br>
 <input type="text" class="form-control" placeholder="Example input" style="visibility: hidden;"><br>
 {{ createadduser_form.submitbuttonuser }}
 </div>
</form>

You're not returning a response when you navigate to /createuser, which will be a GET. You are only returning a response within if createadduser_form.validate_on_submit():, which will only handle the POST call.
I assume you'll be wanting to render the form you've created, like:
return render_template("createuser.html")

Thank you all who paid attention to this topic, I have solved my problem. The thing is that I didn't add the cars page to the html
It turns out that the CSRF check did not pass my request further than the page
{{ {{ create add user_form.hidden_tag () }}
For this check, it is required
if create add user_form.validate_on_submit():
Week, week, week

Related

DRF Create: render_to_string() loses it's context variables when the Response is returned

Background
I want to create and render replies without the need to refresh the page. I know this can be done by submitting the form using AJAX or Fetch(), and use the returned response to append to the bottom of the comment list. I am trying to accomplish this using DRF and AJAX. I opted in to DRF HTMLRenderer + Django render_to_string() so I do not have to create a JS template literal to render the template from JSON, and it would also be a lot easier for me to make any template changes if I just let the Django templating system do it for me.
Problem
My response is not populating my template with context variables, despite me passing in the context to the built in render_to_string(). The chances of render_to_string() being at fault is very low, and I am honestly not sure how to resolve this. I also tried switching out the render_to_string() with render() to see if that would somehow fix the problem. However, the problem still remained.
I know this because of the following two attribute errors when viewing the response from the console:
'str' object has no attribute 'is_authenticated'
Reverse for 'profile_detail' with arguments '('',)' not found. 1 pattern(s) tried: ['account/user/(?P<slug>[^/]+)/$']
Both of which would not be happening if the context was being evaluated in my template.
The actual reply itself is created and visible if I manually refresh the page after the AJAX post.
Information
There does not seem to be a problem with the actual context, because the break point shows the expected results (... is me replacing the actual text for brevity):
{'reply': <Reply: Reply object (47527)>, 'post': <Post: ....>, 'recipient': <Profile: ....>}}
Edit:
When I print print(response['render_reply']) the template is populated, however once it returns in return Response(response), the template is no longer populated with the reply object.
Questions
Is my problem happening with the render_to_string(), or is there something else at fault?
Am I on the right track to sending and rendering replies? Is there anything that can be improved? (code review)
So the problem is most likely occurring here, but that would be really odd because what are the chances of a built in function not working?
response['render_reply'] = render_to_string(
template_name=self.template_name, context=context, request=request
)
Relevant code
Viewset
I created my own action because I wasn't quite sure how to accomplish this with the default create().
class ReplyActionViewSet(viewsets.ModelViewSet):
queryset = Reply.objects.all()
serializer_class = ReplySerializer
permission_classes = [IsAuthenticated]
renderer_classes = [JSONRenderer, TemplateHTMLRenderer]
template_name = "post/partials/render-reply.html"
def get_queryset(self):
return self.queryset.filter(user=self.request.user)
#action(detail=True, methods=['post'])
def create_reply(self, request, pk=None):
response = {}
post = get_object_or_404(
Post.public_or_member_objects.all(), pk=pk
)
serializer = ReplySerializer(data=request.POST)
if serializer.is_valid():
...
reply = Reply.objects.create(**data)
...
context = {'reply': reply, 'post': post, 'data': {"post": post, "recipient": reply.recipient}}
response['render_reply'] = render_to_string(
template_name=self.template_name, context=context, request=request
)
return Response(response)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Snippet of the reply template where one of the issues is happening:
<div class="d-flex flex-row align-items-center">
<div class="avatar avatar-sm me-2" style="background-color:{{ post.user.avatar_color }};">
{{ reply.user.nickname|slice:1 }}
</div>
<a href="{% url "profile_detail" reply.user.username %}" class="text-decoration-none">
<span style="font-weight: 500; color:{{ post.user.avatar_color }};">{{ reply.user.nickname }}</span>
</a>
</div>
And here is my JS:
'use strict';
$(document).on("submit", ".js-reply-form", function (event) {
event.preventDefault();
const form = $(this);
const url = form.attr('action');
$.ajax({
type: "POST",
url: url,
dataType: 'html',
data: form.serialize(),
success: function (data) {
form.trigger('reset');
},
error: function (response) {
console.log(response);
console.log("failed!");
},
});
});
Included trace:
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8000/api/v1/reply-actions/42874/create_reply/
Django Version: 3.2.7
Python Version: 3.10.2
Installed Applications:
Template error:
In template C:\Users\...\Documents\Repo\drf_project\journal\templates\journal\partials\reply-render-reply.html, error at line 36
'str' object has no attribute 'is_authenticated'
26 : </div>
27 :
28 : <div>
29 : {% if reply.user.is_premium %}
30 : <span title="{% trans "drf_project Premium" %}" class="px-1">
31 : <i class="fas fa-crown fa-fw"></i>
32 : </span>
33 : {% endif %}
34 :
35 : <span title="{% trans "X ratio" %}" class="px-1">
36 : <i class="fas fa-percentage"></i> {{ reply.user|get_X_ratio }}
37 : </span>
38 : </div>
39 : </div>
40 :
41 : <!-- Reply body -->
42 : <div>
43 : <div class="small text-muted my-2">{{ reply.date }}</div>
44 :
45 : <!-- Quoted content -->
46 : {% if reply.y_row_id %}
Traceback (most recent call last):
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\django\core\handlers\base.py", line 204, in _get_response
response = response.render()
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\django\template\response.py", line 105, in render
self.content = self.rendered_content
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\rest_framework\response.py", line 70, in rendered_content
ret = renderer.render(self.data, accepted_media_type, context)
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\rest_framework\renderers.py", line 167, in render
return template.render(context, request=request)
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\django\template\backends\django.py", line 61, in render
return self.template.render(context)
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\django\template\base.py", line 170, in render
return self._render(context)
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\django\test\utils.py", line 100, in instrumented_test_render
return self.nodelist.render(context)
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\django\template\base.py", line 938, in render
bit = node.render_annotated(context)
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
return self.render(context)
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\django\template\base.py", line 988, in render
output = self.filter_expression.resolve(context)
File "C:\Users\...\Documents\Repo\drf_project\venv\lib\site-packages\django\template\base.py", line 698, in resolve
new_obj = func(obj, *arg_vals)
File "C:\Users\...\Documents\Repo\drf_project\journal\templatetags\navbar_tags.py", line 15, in get_X_ratio
if user.is_authenticated:
Exception Type: AttributeError at /api/v1/reply-actions/42874/create_reply/
Exception Value: 'str' object has no attribute 'is_authenticated'
Please post the whole trace for the 1st error
<str> object has no ...
Your 2nd error means that in
<a href="{% url "profile_detail" reply.user.username %}"
the username is empty.
The solution was honestly quite straightforward. response['render_reply'] evaluated to {'render_reply':'long string'} which is JSON.
So I needed to change the dataType in my AJAX post to use json instead of html.
I also just passed in the rendered template so I did not have to call data["render_reply"].
context = {
'reply': reply,
'post': post,
'recipient': reply.recipient
}
rendered_template = render_to_string(
template_name='journal/partials/reply-render-reply.html',
context=context,
request=request
)
return Response(rendered_template)

Django Reverse Error upon attempting to delete account

I am unsure of what went wrong but I cannot delete my own account.
I receive the following error:
Reverse for 'delete_account' with keyword arguments '{'user_id': 'testuser1'}' not found. 1 pattern(s) tried: ['account/delete/(?P[^/]+)$']
NoReverseMatch at /account/2/
Views.py
def delete_user(request, username):
if request.method == 'DELETE':
try:
user = request.user
user.delete()
context['msg'] = 'Bye Bye'
except Exception as e:
context['msg'] = 'Something went wrong!'
else:
context['msg'] = 'Request method should be "DELETE"!'
return render(request, 'HomeFeed/snippets/home.html', context=context)
urls.py
from account.views import (
delete_user,
)
path('delete/<username>', delete_user, name='delete_account'),
account.html
<a class="mt-4 btn btn-danger deleteaccount" onclick="return confirm('Are you sure you want to delete your account')" href="{% url 'account:delete_account' user_id=request.user.username %}">Delete Account</a>
traceback
File "/lib/python3.8/site-packages/django/template/base.py", line 904, in render_annotated
return self.render(context)
File "/lib/python3.8/site-packages/django/template/defaulttags.py", line 443, in render
url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
File "/lib/python3.8/site-packages/django/urls/base.py", line 90, in reverse
return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
File "/lib/python3.8/site-packages/django/urls/resolvers.py", line 673, in _reverse_with_prefix
raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'delete_account' with keyword arguments '{'user_id': 'testuser1'}' not found. 1 pattern(s) tried: ['account/delete/(?P<username>[^/]+)$']
I am not 100% sure if my answer would be correct, but you can give it a try.
<a class="mt-4 btn btn-danger deleteaccount" onclick="return confirm('Are you sure you want to delete your account')" href="{% url 'account:delete_account' user_id=request.user.username %}">Delete Account</a>
Change the user_id=request.user.username to either username=request.user.username or simply remove the first part request.user.username
It should work according to me. If not do let me know.
EDIT
you must change your code from
try:
user = request.user #this line
user.delete()
context['msg'] = 'Bye Bye'
except Exception as e:
context['msg'] = 'Something went wrong!'
to
try:
user = User.objects.get(username = request.user.username) # alternatively you could do ```User.objects.get(pk=request.user.pk)```
user.delete()
context['msg'] = 'Bye Bye'
except Exception as e:
context['msg'] = 'Something went wrong!'

flask mail error “SMTPServerDisconnected('please run connect() first')”

I am writing a little web application based on Miguel Grinberg's Flasky. I use the exact same code for user send reset password mail using gmail.
The following as my email.py file here i can implement mail sending function
def send_password_reset_email(user):
token = user.get_reset_password_token()
send_email(_('[Microblog] Reset Your Password'),
sender=current_app.config['ADMINS'][0],
recipients=[user.email],
text_body=render_template('email/reset_password.txt',
user=user, token=token),
html_body=render_template('email/reset_password.html',
user=user, token=token))
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
def send_email(subject, sender, recipients, text_body, html_body):
msg = Message(subject, sender=sender, recipients=recipients)
msg.body = text_body
msg.html = html_body
Thread(target=send_async_email,
args=(current_app._get_current_object(), msg)).start()
In routes.py file im getting email from the user and if the user email match then i well send the token to the user via mail
#bp.route('/reset_password_request', methods=['GET', 'POST'])
def reset_password_request():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
form = ResetPasswordRequestForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user:
send_password_reset_email(user)
flash(
_('Check your email for the instructions to reset your password'))
return redirect(url_for('auth.login'))
return render_template('auth/reset_password_request.html',
title=_('Reset Password'), form=form)
#bp.route('/reset_password/<token>', methods=['GET', 'POST'])
def reset_password(token):
if current_user.is_authenticated:
return redirect(url_for('main.index'))
user = User.verify_reset_password_token(token)
if not user:
return redirect(url_for('main.index'))
form = ResetPasswordForm()
if form.validate_on_submit():
user.set_password(form.password.data)
db.session.commit()
flash(_('Your password has been reset.'))
return redirect(url_for('auth.login'))
return render_template('auth/reset_password.html', form=form)
In model.py file in the user model i generate a token for a user and also check the user token
def get_reset_password_token(self, expires_in=600):
return jwt.encode(
{'reset_password': self.id, 'exp': time() + expires_in},
current_app.config['SECRET_KEY'],
algorithm='HS256').decode('utf-8')
#staticmethod
def varify_reset_password_token(token):
try:
id = jwt.decode(token, current_app.config['SECRET_KEY'],
algorithms=['HS256'])['reset_password']
except:
return
return User.query.get(id)
my flask mail setup is as follows config.py file
MAIL_SERVER = os.environ.get('MAIL_SERVER')
MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25)
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
ADMINS =['socialtraffic#gmail.com']
The following Error i get in the terminal
Traceback (most recent call last):
File "c:\python38\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "c:\python38\lib\threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\Ijaz Bacha\project\microblog1\app\email.py", line 9, in send_async_email
mail.send(msg)
File "c:\users\ijaz bacha\project\microblog1\venv\lib\site-packages\flask_mail.py", line 492, in send
message.send(connection)
File "c:\users\ijaz bacha\project\microblog1\venv\lib\site-packages\flask_mail.py", line 152, in __exit__
self.host.quit()
File "c:\python38\lib\smtplib.py", line 988, in quit
res = self.docmd("quit")
File "c:\python38\lib\smtplib.py", line 424, in docmd
self.putcmd(cmd, args)
File "c:\python38\lib\smtplib.py", line 371, in putcmd
self.send(str)
File "c:\python38\lib\smtplib.py", line 363, in send
raise SMTPServerDisconnected('please run connect() first')
smtplib.SMTPServerDisconnected: please run connect() first
I am also doing the same tutorial and ran into the same problem. I found the answer on Miguel's Blog:
You need two terminal windows.
The first terminal running your local mail server that emulates your emails being sent:
$(venv) python -m smtpd -n -c DebuggingServer localhost:8025
Your main flask terminal window with the following required commands (FLASK_DEBUG=1 is optional but highly recommended for troubleshooting):
$ export FLASK_APP=microblog.py
$ export FLASK_DEBUG=1
$ export MAIL_SERVER=localhost
$ export MAIL_PORT=8025
$ flask run
This solved my problems.
In my experience, a while ago I had a very similar issue that you you were having. After troubleshooting, I found out that my code worked when I would create a mail class, and call function like $mailclass.ehlo etc.
Based on the error its having an issue connecting or staying connected. Try calling the connect methods in the function itself and close of the connection after each email.
I decided to change the following line in the app/__init__.py file:
mail = Mail(app)
with:
mail = Mail()
mail.init_app(app)
Solved the issue for me

Problem with initiating form fields as instance variables in form classes

Not able to have a instance variable of WTForm fields as instance variables
This is to have multiple number (flexible) of field which can be cascaded to increase number of fields.
The program is working fine for a simple class and one login field and one password field if the field are class variables..
project/app/froms.py
class LoginForm(FlaskForm):
username = StringField('Username')
password = PasswordField('Password')
if the fields are initiated in the constructors, the program is not working. the error of the program is
project/app/forms.py
class TestLoginForm(FlaskForm):
def __init__(self):
username = StringField('Username')
password = PasswordField('Password')
the following are other parts of this program
<!-- project/app/templates/test.html -->
<!DOCTYPE html>
<html>
<head>
<title>Login Page</title>
</head>
<body>
<h1>Sign In</h1>
<form method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br>
{{ form.username(size=32) }}
</p>
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }}
</p>
<p>{{ form.submit() }}</p>
</form>
</body>
</html>
project/app/routes.py
from app import app
from flask import render_template
from app.forms import TestLoginForm
#app.route('/', methods=['GET','POST'])
#app.route('/login', methods=['GET','POST'])
def index():
form = TestLoginForm()
return render_template('test.html', form=form)
project/app/init.py
from flask import Flask
app = Flask(__name__)
app.config['SECRET_KEY'] = 'you-will-never-guess'
from app import routes
project/ website.py
from app import app
Please let me know what are the concepts I need to learn and advise about possible way to get the outcome of the problem.
Traceback (most recent call last):
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\css120807\Documents\Flask_testWebsite\app\routes.py", line 13, in index
return render_template('test.html', form=form)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\templating.py", line 135, in render_template
context, ctx.app)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask\templating.py", line 117, in _render
rv = template.render(context)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\jinja2\asyncsupport.py", line 76, in render
return original_render(self, *args, **kwargs)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\jinja2\environment.py", line 1008, in render
return self.environment.handle_exception(exc_info, True)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\jinja2\environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\jinja2\_compat.py", line 37, in reraise
raise value.with_traceback(tb)
File "C:\Users\css120807\Documents\Flask_testWebsite\app\templates\test.html", line 10, in top-level template code
{{ form.hidden_tag() }}
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask_wtf\form.py", line 135, in hidden_tag
u'\n'.join(text_type(f) for f in hidden_fields(fields or self))
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask_wtf\form.py", line 135, in <genexpr>
u'\n'.join(text_type(f) for f in hidden_fields(fields or self))
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\flask_wtf\form.py", line 125, in hidden_fields
for f in fields:
File "C:\Users\css120807\AppData\Local\Continuum\anaconda3\lib\site-packages\wtforms\form.py", line 57, in __iter__
return iter(itervalues(self._fields))
AttributeError: 'TestLoginForm' object has no attribute '_fields'
In quickstart there is an example of creating forms:
https://flask-wtf.readthedocs.io/en/stable/quickstart.html#creating-forms
There are class fields, not instance (in __init__).
If I understand correctly you would like to inherit fields from parent class, why not like this:
class MyForm(FlaskForm):
name = StringField('name', validators=[DataRequired()])
class AnotherForm(MyForm):
surname = StringField('surname', validators=[DataRequired()])
then you can use two forms in your routes.py:
form = MyForm()
with csrf token and name field
or
form = AnotherForm()
with everything from MyForm (csrf + name) and surname

How to create delegate/nested async context manager for aiohttp?

I want to create custom request manager for crawler with dynamic waiting.
My crawler need to make requests to sites which prohibit parallel requests from same ip address. If such blocking occurs requests returns with HTTP error codes 403, 503, 429, etc.
In case of error I want to wait some time and repeat request. But for simplicity of parsers they just call get and receive correct page.
I want to use aiohttp and new async with syntax of Python 3.5 so my parsers classes can use async with for my requester class same way if they used aiohttp.ClientSession like this:
# somewhere in a parser
async def get_page(self, requester, page_index):
async with requester.get(URL_FMT.format(page_index)) as response:
html_content = await response.read()
result = self.parsing_page(html_content)
return result
if requester is aiohttp.ClientSession, then response is aiohtpp.ClientResponse which have __aenter__ and __aexit__ methods, so async with working as expected.
But if I put my requester class in the middle it is not working anymore.
Traceback (most recent call last):
File "/opt/project/api/tornado_runner.py", line 6, in <module>
from api import app
File "/opt/project/api/api.py", line 20, in <module>
loop.run_until_complete(session.login())
File "/usr/local/lib/python3.5/asyncio/base_events.py", line 337, in run_until_complete
return future.result()
File "/usr/local/lib/python3.5/asyncio/futures.py", line 274, in result
raise self._exception
File "/usr/local/lib/python3.5/asyncio/tasks.py", line 239, in _step
result = coro.send(None)
File "/opt/project/api/viudata/session.py", line 72, in login
async with self.get('https://www.viudata.com') as resp:
AttributeError: __aexit__
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x7f44f61ef240>
It is looking like this.
class Requester:
def __init__(self, session: aiohttp.ClientSession):
self.session = session
async def get(self, *args, **kwargs):
is_result_successful = False
while not is_result_successful:
response = await self.session.get(*args, **kwargs)
if response.status in [503, 403, 429]:
await self.wait_some_time()
else:
is_result_successful = True
return response
From my understanding self.session.get is coroutine function so I will await it. Result is aiohttp.ClientResponse which have __aenter__ or __aexit__. But if return it parser's code of async with block return odd error.
Can you say what I need to replace to with my requester class as with aiohttp.ClientSession?
You should write additional code to support async with protocol.
See client.request() and _RequestContextManager for inspiration.

Resources