2012-12-07 32 views
5

Tôi đang cố gắng sử dụng flask.g để lưu các biến có thể được truy cập trong các chức năng khác, nhưng dường như không hoạt động chính xác. Ứng dụng tạo ra lỗi sau khi tôi cố gắng truy cập g.name: AttributeError: '_RequestGlobals' object has no attribute 'name'.Không thể sử dụng flask.g để truy cập các biến trong các chức năng khác

Các documentation cho flask.g nói:

Chỉ cần lưu trữ trên này bất cứ điều gì bạn muốn. Ví dụ một kết nối cơ sở dữ liệu hoặc người dùng hiện đang đăng nhập.

Dưới đây là một hoàn chỉnh, ví dụ tối thiểu để minh họa các lỗi mà tôi nhận được khi cố gắng truy cập các biến bên ngoài của hàm nó đã được tạo ra trong. Bất kỳ Trợ giúp sẽ được đánh giá cao.

#!/usr/bin/env python 

from flask import Flask, render_template_string, request, redirect, url_for, g 
from wtforms import Form, TextField 

application = app = Flask('wsgi') 

@app.route('/', methods=['GET', 'POST']) 
def index(): 
    form = LoginForm(request.form) 

    if request.method == 'POST' and form.validate(): 
     name = form.name.data 
     g.name = name 

     # Need to create an instance of a class and access that in another route 
     #g.api = CustomApi(name) 

     return redirect(url_for('get_posts')) 

    else: 

     return render_template_string(template_form, form=form) 

@app.route('/posts', methods=['GET']) 
def get_posts(): 
    # Need to access the instance of CustomApi here 
    #api = g.api 
    name = g.name 
    return render_template_string(name_template, name=name) 


class LoginForm(Form): 
    name = TextField('Name') 

template_form = """ 
{% block content %} 
<h1>Enter your name</h1> 

<form method="POST" action="/"> 
    <div>{{ form.name.label }} {{ form.name() }}</div><br> 
    <button type="submit" class="btn">Submit</button>  
</form> 
{% endblock %} 

""" 

name_template = """ 
{% block content %} 

    <div>"Hello {{ name }}"</div><br> 

{% endblock %} 

""" 

if __name__ == '__main__': 
    app.run(debug=True) 

Trả lời

2

Nếu bạn cần theo dõi thông tin xác thực, tôi khuyên bạn nên sử dụng một trong các plugin Flask như Flask-Login hoặc Flask-Principal.

Ví dụ: chúng tôi sử dụng Flask-Principal. Nó làm tăng tín hiệu nhận dạng khi ai đó xác thực (hoặc nó phát hiện một cookie xác thực). Sau đó chúng tôi ánh xạ danh tính đã đăng nhập của họ với người dùng trong cơ sở dữ liệu của chúng tôi. Một cái gì đó như thế này:

# not actual code 
@identity_loaded.connect_via(app) 
def on_identity_loaded(sender, identity): 
    user = Person.query.filter(Person.username==identity.person.username).one() 
    g.user = user 

và sau đó chúng tôi có thể sử dụng g.user trong bất kỳ bộ điều khiển hoặc mẫu nào. (Chúng tôi thực sự trích xuất rất nhiều điều này, đó là một hack dễ dàng, lười biếng gây ra nhiều rắc rối hơn giá trị của nó.)

Nếu bạn không muốn sử dụng mô-đun, có tín hiệu tích hợp sẵn có thể móc vào lúc bắt đầu của mọi yêu cầu:

http://flask.pocoo.org/docs/tutorial/dbcon/

# This runs before every request 
@app.before_request 
def before_request(): 
    g.user = your_magic_user_function() 

và g.user sau đó sẽ là kỳ diệu có sẵn ở khắp mọi nơi.

Tôi hy vọng điều đó sẽ hữu ích!

+0

Sự cố khi sử dụng @ app.before_request trong trường hợp của tôi là tôi cần nhận thông tin về tên người dùng và mật khẩu từ người dùng để sử dụng magic_user_function() của mình. Tôi sẽ kiểm tra các mô-đun mà bạn đã đề cập. – Raj

+0

Nghĩ rằng tôi sẽ theo dõi để cho bạn biết rằng đây là những gì tôi đã làm. Tôi đã phải viết lại wrapper của tôi để hỗ trợ phương pháp này, nhưng nó không quá tệ. Cảm ơn câu trả lời cho câu hỏi Flask của tôi btw Rachel! – Raj

13

Đối tượng g là một đối tượng yêu cầu dựa trên và không tồn tại giữa các yêu cầu, ví dụ: g được tái tạo giữa yêu cầu của bạn để index và yêu cầu của bạn để get_posts.

Application Globals in Flask:

Flask cung cấp cho bạn với một đối tượng đặc biệt để đảm bảo nó chỉ có giá trị đối với các yêu cầu hoạt động và điều đó sẽ trở lại giá trị khác nhau cho mỗi yêu cầu. Tóm lại: nó làm điều đúng, giống như nó yêu cầu và phiên làm việc.

Để lưu trữ liên tục dữ liệu nhỏ giữa các yêu cầu sử dụng sessions thay thế. Bạn có thể (nhưng không nên) lấy đi bằng cách lưu trữ dữ liệu trong đối tượng app trực tiếp cho trạng thái ứng dụng toàn cầu (tất cả các phiên), tương tự như những gì config thực hiện, nếu bạn tìm thấy lý do thực sự tốt để làm như vậy.

Để có cơ sở dữ liệu sử dụng dữ liệu phức tạp hơn.

+1

Tôi hiểu câu trả lời của bạn cho bit nhỏ của thông tin như biến đơn giản, nhưng làm thế nào để tạo ra một thể hiện của một lớp học và chia sẻ rằng qua nhiều chức năng? Cụ thể là tôi đang tạo một thể hiện của một lớp trả về thông tin xác thực và tôi muốn sử dụng dữ liệu trả về đó trong nhiều tuyến. – Raj

+0

Sử dụng 'phiên' để xây dựng lại các đối tượng của bạn qua các yêu cầu sẽ là cách dễ nhất để thực hiện. Giống như lưu trữ 'user_id', có thể. Tuần tự hóa cũng có thể hoạt động. Chọn phương pháp với ít chi phí và dễ đọc nhất và ý nghĩa nhất. – soulseekah

+1

@Raj Đây phải là câu trả lời được chấp nhận vì nó xác định lý do tại sao 'g.users' không hoạt động cho bạn. –

1

Chỉ cần sử dụng các phiên trong bình. Trong trường hợp của bạn, bạn chỉ muốn lưu người dùng/tên trong yêu cầu của bạn và cách dễ nhất là sử dụng các phiên.

from flask import session 
app.secret_key = 'some key for session' 

Sau đó, chức năng của bạn có thể được thay đổi như sau:

@app.route('/', methods=['GET', 'POST']) 
def index(): 
    form = LoginForm(request.form) 
    if request.method == 'POST' and form.validate(): 
     session['name'] = form.name.data 
     return redirect(url_for('get_posts')) 
    else: 
     return render_template_string(template_form, form=form) 

@app.route('/posts', methods=['GET']) 
def get_posts(): 
    if 'name' in session: 
     name = session['name'] 
    else: 
     name = "Unknown" 
    return render_template_string(name_template, name=name) 
Các vấn đề liên quan