Docs Menu
Docs Home
/ /

Flask와 셀러리 통합

이 튜토리얼에서는 MongoDB , Flask, 셀러리를 사용하여 뉴스레터 플랫폼을 빌드 방법을 학습 수 있습니다. 이 애플리케이션 통해 사용자는 뉴스레터를 구독 하고 관리자는 배치 이메일을 비동기적으로 관리 하고 보낼 수 있습니다.

Flask는 프로젝트 전반에서 개발자에게 일관성 제공하는 내장 경량 웹 애플리케이션 프레임워크 입니다. 자세한 내용은 Flask 웹페이지를 참조하세요.

셀러리는 대량의 메시지를 효율적으로 처리하는 오픈 소스 분산된 작업 대기열입니다. 비동기 처리 및 작업 스케줄링을 지원합니다. 자세한 내용은 셀러리 웹 페이지를 참조하세요.

이 튜토리얼에서는 JavaScript, Flask 및 MongoDB 사용하는 뉴스레터 플랫폼 샘플 프로젝트 Github 리포지토리에서 샘플 애플리케이션 다시 만듭니다.

이 튜토리얼을 시작하기 전에 다음 구성 요소가 설치 및 설정하다 있는지 확인하십시오.

  • MongoDB cluster. Atlas 사용하는 것이 좋습니다. Atlas cluster 만드는 방법을 학습 Atlas 설명서의 Get Started with Atlas (Atlas 시작하기) 페이지를 참조하세요.

  • 클러스터 에 있는 newsletter 데이터베이스 . 자세한 내용은 Atlas 가이드의 데이터베이스 생성 페이지를 참조하세요.

  • 셀러리의 메시지 브로커로 사용할 래빗MQ.

  • Gmail 을 SMTP 서버로 사용할 수 있습니다. SMTP 서버에 대한 자세한 내용은 단순 메일 전송 프로토콜 위키백과 페이지를 참조하세요.

  • Python 3.9 이상

1

프로젝트 디렉토리 의 이름은 newsletter입니다. 디렉토리 생성하고 터미널에서 다음 명령을 실행 디렉토리로 이동합니다.

mkdir newsletter
cd newsletter

다음 파일에는 애플리케이션 의 코드가 들어 있습니다.

  • app.py: Flask 애플리케이션 의 기본 진입 점 .

  • config.py: MongoDB 연결 URI, 메일 서버 구성, 셀러리 브로커 연결 및 기타 환경별 변수를 포함한 애플리케이션 의 구성 설정입니다.

  • tasks.py: 이메일을 비동기적으로 전송하는 배경 작업을 정의합니다.

  • routes.py: 애플리케이션 이 응답하는 경로(URL)를 정의합니다.

애플리케이션 애플리케이션 모듈식으로 만들고 유지 관리하기 쉽게 만들 수 있는 별도의 고려 사항으로 애플리케이션 구조화하는 것이 좋습니다.

프로젝트 디렉토리 에서 다음 구조를 만듭니다.

newsletter/
├── app.py
├── config.py
├── routes.py
├── tasks.py
├── templates/
│ ├── admin.html
│ └── subscribe.html
└── static/
└── styles.css
2

애플리케이션 다음 라이브러리를 사용합니다.

  • 웹 서버 및 라우팅 처리를 위한 Flask

  • 애플리케이션 에서 이메일을 전송하기위한 Flask-mail

  • PyMongo

  • 배치 이메일 전송과 같은 작업을 관리 하는 셀러리

가상 환경 사용

Python 가상 환경 을 사용하면 프로젝트마다 다양한 버전의 라이브러리를 설치할 수 있습니다. pip 명령을 실행 전에 virtualenv 가 활성화되어 있는지 확인합니다.

터미널에서 다음 pip 명령을 실행하여 종속성을 설치합니다.

pip install flask-pymongo Flask-Mail celery

config.py 파일 에는 다음 작업을 수행하기 위한 설정 및 자격 증명 포함되어 있습니다.

  • 메시지 브로커로 셀러리를 래빗MQ에 연결

  • Gmail을 SMTP 서버 로 사용하도록 Flask-mail 구성

  • 애플리케이션 MongoDB deployment 에 연결

config.py 파일 에 다음 코드를 추가하여 필요한 구성을 정의합니다.

import os
class Config:
MAIL_USERNAME = '<username>' # Your email address without '@gmail.com'
MAIL_PASSWORD = '<app password>'
MAIL_DEFAULT_SENDER = '<email address>'
MONGO_URI = '<mongodb connection string>'
DATABASE_NAME = "newsletter"
ALLOWED_IPS = ['127.0.0.1']
MAIL_SERVER = 'smtp.gmail.com'
MAIL_PORT = 587
MAIL_USE_TLS = True
CELERY_BROKER_URL = 'amqp://guest:guest@localhost//'
RESULT_BACKEND = MONGO_URI + '/celery_results'

애플리케이션 에서 이메일을 보내 활성화 Gmail 자격 증명 과 이메일 (MAIL_USERNAME, MAIL_PASSWORD, MAIL_DEFAULT_SENDER)을 제공해야 합니다. 보안을 위해 프라이머리 비밀번호를 사용하는 대신 사용할 앱 비밀번호를 생성하는 것이 좋습니다. 자세한 내용은 Google 계정의 앱 비밀번호 설정 을 참조하세요.

또한 MONGO_URI 환경 변수로 설정하다 연결 문자열 제공해야 합니다. 자세한 내용은 이 가이드의 연결 문자열 만들기 섹션을 참조하세요.

제공된 셀러리 브로커 URL (CELERY_BROKER_URL)은 래빗MQ를 브로커로 지정하지만, 다른 구현을 지원 이 URL 사용자 지정할 수 있습니다. 자세한 내용은 셀러리 문서의 브로커 설정 섹션을 참조하세요.

ALLOWED_IPS 목록은 Send Newsletter 페이지에 대한 액세스 제어하는 데 사용됩니다. 나머지 변수는 Flask 및 셀러리 구성 요소를 구성합니다.

app.py 파일 애플리케이션 의 핵심 구성 요소를 초기화하고 구성합니다. 다음 작업을 수행합니다.

  • Flask 애플리케이션 생성하고 구성 상수를 로드합니다.

  • 앱의 메일 서버 설정을 사용하여 Flask-mail 인스턴스 초기화합니다.

  • PyMongo 운전자 사용하여 newsletter MongoDB database 에 연결합니다.

  • Flask 앱 과 선택한 브로커로 구성된 셀러리 인스턴스 생성합니다.

app.py 파일 에 다음 코드를 추가하여 Flask, MongoDB 및 Celery를 초기화합니다.

from flask import Flask
from flask_mail import Mail
from flask_pymongo import PyMongo
from celery import Celery
# Create a Flask application
app = Flask(__name__)
app.config.from_object('config.Config')
# Create a Flask-Mail instance
mail = Mail(app)
# Connect to MongoDB
client = PyMongo(app).cx
db = client[app.config['DATABASE_NAME']]
# Create a Celery instance
celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)
from routes import *
from tasks import *
if __name__ == '__main__':
app.run(debug=True)

셀러리 작업 app.py 파일 에서 인스턴스화된 구성 요소를 사용하여 구독자에게 뉴스레터 이메일 보냅니다.

@celery.task() 데코레이터는 함수를 셀러리 작업 으로 등록합니다. bind=True 을 설정하면 함수가 작업 인스턴스 self 인수로 수신하여 셀러리 작업 메서드 및 메타데이터 액세스 할 수 있음을 의미합니다. 작업에 대한 자세한 내용은 셀러리를 참조하세요. 앱. 작업 API 문서를 참조하세요.

이 작업 Flask의 HTTP 요청 주기 외부에서 실행되므로 이메일 로직을 with app.app_context() 차단 으로 래핑하여 애플리케이션 컨텍스트를 수동으로 제공해야 합니다. 이렇게 하면 Flask-mail mail 인스턴스 및 newsletter MongoDB database 에 대한 PyMongo 연결과 같은 다른 구성 요소에 액세스 할 수 있습니다.

이 함수는 subscribers 목록을 반복하고,Flask-mail Message 클래스를 사용하여 이메일 만든 다음 mail 객체 사용하여 각 사용자에게 보냅니다. 각 이메일 전송된 후 MongoDB deliveries 컬렉션 에 문서 삽입하여 메시지가 전송되었음을 기록 하여 전송을 기록합니다. 각 이메일 작업은 try 차단 으로 래핑되어 오류 발생 시 실패가 기록되고 데이터베이스 잘못된 전송 기록 으로 업데이트되지 않습니다.

tasks.py 파일 에 다음 코드를 추가하여 send_emails() 함수를 정의합니다.

from flask_mail import Message
from app import app, mail, db, celery
from datetime import datetime
@celery.task(bind=True)
def send_emails(self, subscribers, title, body):
with app.app_context():
for subscriber in subscribers:
try:
print(f"Sending email to {subscriber['email']}")
msg = Message(title, recipients=[subscriber['email']])
msg.body = body
mail.send(msg)
db.deliveries.insert_one({
'email': subscriber['email'],
'title': title,
'body': body,
'delivered_at': datetime.utcnow()
})
print("Email sent")
except Exception as e:
print(f"Failed to send email to {subscriber['email']}: {str(e)}")
return {'result': 'All emails sent'}

Flask에서 @app.route() 데코레이터는 특정 함수에 URL 경로를 할당합니다. 다음 코드에서는 루트(/), /admin, /subscribe/send-newsletters 경로를 정의하는 데 사용됩니다. 선택적 methods 매개변수는 일부 인스턴스에서 허용되는 HTTP 메서드 목록을 정의하는 데 사용됩니다.

@app.before_request() 데코레이터는 모든 요청 전에 실행 함수를 설정합니다. 이 경우 함수는 admin 페이지에 대한 액세스 config.py 파일 에 정의된 ALLOWED_IPS 매개변수에 나열된 IP 주소로 제한하여 몇 가지 기본 보안을 제공합니다. 특히 localhost에 대해서만 액세스 허용됩니다.

루트 및 /admin 라우팅은 render_template() 메서드를 사용하여 페이지를 렌더링합니다. /subscribe/send-newslettersrequest.form[] 의 액세스 요청 매개 변수를 라우팅하여 명령을 실행한 다음 HTTP 응답을 반환합니다.

routes.py 파일 에 다음 코드를 추가하여 경로를 정의합니다.

from flask import render_template, request, abort, jsonify
from app import app, db
from tasks import send_emails
@app.before_request
def limit_remote_addr():
if 'X-Forwarded-For' in request.headers:
remote_addr = request.headers['X-Forwarded-For'].split(',')[0]
else:
remote_addr = request.remote_addr
if request.endpoint == 'admin' and remote_addr not in app.config['ALLOWED_IPS']:
abort(403)
@app.route('/')
def home():
return render_template('subscribe.html')
@app.route('/admin')
def admin():
return render_template('admin.html')
@app.route('/subscribe', methods=['POST'])
def subscribe():
first_name = request.form['firstname']
last_name = request.form['lastname']
email = request.form['email']
if db.users.find_one({'email': email}):
return """
<div class="response error">
<span class="icon">&#x2716;</span> This email is already subscribed!
</div>
""", 409
db.users.insert_one({'firstname': first_name, 'lastname': last_name, 'email': email, 'subscribed': True})
return """
<div class="response success">
<span class="icon">&#x2714;</span> Subscribed successfully!
</div>
""", 200
@app.route('/send-newsletters', methods=['POST'])
def send_newsletters():
title = request.form['title']
body = request.form['body']
subscribers = list(db.users.find({'subscribed': True}))
for subscriber in subscribers:
subscriber['_id'] = str(subscriber['_id'])
send_emails.apply_async(args=[subscribers, title, body])
return jsonify({'message': 'Emails are being sent!'}), 202

이 파일 에서 더 많은 보안 보호 기능을 추가하거나 애플리케이션 에 대한 사용자 대상 경고를 사용자 지정할 수 있습니다.

templates 디렉토리 의 HTML 파일은 사용자 인터페이스를 정의하며 표준 HTML을 사용하여 작성됩니다. 이 애플리케이션 비동기 HTTP 요청을 사용하기 때문에 이러한 파일의 스크립트는 Fetch API 호출를 사용합니다. 이러한 스크립트는 시간 초과 및 오류도 처리하다 .

다음 코드를 subscribe.html 파일 에 복사하여 Subscribe to Newsletter 페이지를 만듭니다.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Subscribe to Newsletter</title>
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<h1>Subscribe to our Newsletter</h1>
<form id="subscribe-form">
<label for="firstname">First Name:</label>
<input type="text" id="firstname" name="firstname" required>
<br>
<label for="lastname">Last Name:</label>
<input type="text" id="lastname" name="lastname" required>
<br>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<br>
<button type="submit">Subscribe</button>
</form>
<div id="response"></div>
<script>
document.getElementById('subscribe-form').addEventListener('submit', function(event) {
event.preventDefault();
var formData = new FormData(event.target);
fetch('/subscribe', {
method: 'POST',
body: formData
}).then(response => {
if (!response.ok) {
throw response;
}
return response.text();
}).then(data => {
document.getElementById('response').innerHTML = data;
document.getElementById('subscribe-form').reset();
setTimeout(() => {
document.getElementById('response').innerHTML = '';
}, 3000);
}).catch(error => {
error.text().then(errorMessage => {
document.getElementById('response').innerHTML = errorMessage;
setTimeout(() => {
document.getElementById('response').innerHTML = '';
}, 3000);
});
});
});
</script>
</body>
</html>

관리자 페이지 스크립트 send_newsletter 호출의 성공 나타내는 경고 사용자에게 표시합니다.

다음 코드를 admin.html 파일 에 복사하여 Send Newsletter 페이지를 만듭니다.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin - Send Newsletter</title>
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<h1>Send Newsletter</h1>
<form id="admin-form">
<label for="title">Title:</label>
<input type="text" id="title" name="title" required>
<br>
<label for="body">Body:</label>
<textarea id="body" name="body" required></textarea>
<br>
<button type="submit">Send</button>
</form>
<div id="response"></div>
<script>
document.getElementById('admin-form').addEventListener('submit', function(event) {
event.preventDefault();
var formData = new FormData(event.target);
fetch('/send-newsletters', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(() => {
document.getElementById('response').innerText = 'Emails are being sent!';
setTimeout(() => {
document.getElementById('response').innerText = '';
}, 3000);
document.getElementById('admin-form').reset();
})
.catch(error => {
document.getElementById('response').innerText = 'Error sending emails.';
setTimeout(() => {
document.getElementById('response').innerText = '';
}, 3000);
console.error('Error:', error);
});
});
</script>
</body>
</html>

styles.css 파일 에 다음 코드를 추가하여 템플릿에 스타일시트 적용 할 수 있습니다.

body {
font-family: system-ui;
font-optical-sizing: auto;
font-weight: 300;
font-style: normal;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #040100;
}
h1 {
color: white;
}
form {
background: #023430;
padding: 30px 40px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 400px;
margin: 20px 0;
}
label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: white;
}
input[type="text"],
input[type="email"],
textarea {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
}
button {
background: #00ED64;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
font-family: "Nunito", sans-serif;
}
button:hover {
background: #00684A;
}
#response {
margin-top: 20px;
font-size: 16px;
color: #28a745;
}
footer {
text-align: center;
padding: 20px;
margin-top: 20px;
font-size: 16px;
color: #666;
}

이전 단계를 완료하면 MongoDB , Flask 및 Celery를 사용하여 뉴스레터 플랫폼을 관리 애플리케이션 작동하는 것입니다.

다음 단계에 따라 애플리케이션 테스트할 수 있습니다.

1

래빗MQ 노드 시작합니다. 자세한 내용은 운영 체제의 래빗MQ 설명서 를 참조하세요.

MacOS의 경우:

brew services start rabbitmq

Windows의 경우:

rabbitmq-service start

On Linux/Unix:

sudo systemctl start rabbitmq-server
2

다음 코드를 사용하여 애플리케이션 시작합니다.

flask --app app run

다른 터미널에서 셀러리 작업자를 시작합니다.

celery -A app.celery worker --loglevel=info
3

브라우저에서 localhost:5000 로 이동하여 Subscribe to our Newsletter 페이지를 엽니다.

구독자 정보를 입력하고 Subscribe을(를) 클릭합니다.

새 구독자를 생성했는지 확인하려면 Atlas 열고 newsletter 데이터베이스 에서 users 컬렉션 으로 이동합니다.

4

브라우저에서 localhost:5000/admin 으로 이동하여 Send Newsletter 페이지를 엽니다. 뉴스레터 세부 정보를 입력하고 Send을 클릭합니다.

셀러리 작업자 로그 다음 이미지와 유사한 Email sent 로그 항목이 표시됩니다.

[2025-05-27 09:54:43,873: INFO/ForkPoolWorker-7] Task tasks.send_emails[7d7f9616-7b9b-4508-a889-95c35f54fe43] succeeded in 3.93334774998948s: {'result': 'All emails sent'}
[2025-05-27 10:04:52,043: INFO/MainProcess] Task tasks.send_emails[ac2ec70f-2d3e-444a-95bb-185ac659f460] received
[2025-05-27 10:04:52,046: WARNING/ForkPoolWorker-7] Sending email to <subscriber_email>
[2025-05-27 10:04:53,474: WARNING/ForkPoolWorker-7] Email sent

newsletter 데이터베이스 의 deliveries 컬렉션 으로 이동하여 이메일 보냈는지 확인할 수도 있습니다.

이 애플리케이션 Flask 애플리케이션 셀러리 작업 대기열과 통합하여 구독자 데이터를 관리 하고 배치 이메일을 보내는 방법을 보여줍니다. 이 애플리케이션 기반으로 빌드 Flask 또는 셀러리를 실험해 볼 수 있습니다. 몇 가지 가능한 개선 사항에는 다음과 같은 변경 사항이 포함됩니다.

이 튜토리얼에 사용된 구성 요소에 대한 자세한 내용은 다음 리소스를 참조하세요.

지원 찾거나 MongoDB Community 에 기여하려면 MongoDB 개발자 커뮤니티 페이지를 참조하세요.

돌아가기

타사 통합

이 페이지의 내용