Co-authored with Liarrah Lambayao (@ldlambayao)
Have you ever tried to organize your files by placing all of them in a single folder?🤔
Oh, everything quickly became messy and harder to manage. The same way works with software too. When all of the code is placed in a single system, it becomes harder for the developer to manage, maintain, edit and fix the code. Even the possibility of scaling and improving it would become more difficult. This is where MVC Architecture comes in, a clean and structured way to keep everything organized and manageable.
MVC Architecture is a software design that is frequently used by developers in the frontend and backend.
What is MVC Architecture?
MVC stands for Model-View-Controller. It concerns making things easier to manage, maintain, and make the code clear and organized. Projects without MVC are like putting all of your eggs in a single basket; if a single part of the code malfunctions, the whole system is at risk.
Applying MVC would make things easier as it separates the system into three different components/roles: Model, View, and Controller.
The Model holds and manages the data, and in this case, the recipient’s information and certificate data. If the data changes, the model will tell the view about it.
View is what the user sees in the application. It displays the data from the Model and updates when the underlying data changes.
The Controller is what ties everything together. It processes user input and connects the Model and View components. It receives the user input and decides what to do with it.
Project Overview
To demonstrate how MVC is applied in practice, this article walks through the development of a simple automated certificate generator in Python. As certificates are an essential part of recognizing accomplishments and creating them manually can be tedious, this project reads information such as the date, name, etc., from a .txt file and generates certificates accordingly.
Although automating certificates is a common beginner-friendly project that focuses on getting the task done with Python libraries, this article takes a different approach by highlighting how the Model-View-Controller (MVC) architecture can be applied to organize code and build a cleaner, more modular solution.
This article takes an example from a pre-existing repository in GitHub and refactors it into a Model–View–Controller structure. By restructuring the original implementation, this project demonstrates how the separation of concerns can improve clarity, modularity, and scalability.
🔗github repository by gunarakulangunaretnam
- Current Structure of Repository
certificate generator/
|
|----generated-certificates/ # output directory for generated certificate
|
|----run.py # python script
|
|----certificate-template.jpg # certificate template
|
|----name-data.txt/.xlsx # file that contains recipients
- Python Script
import os
import cv2
list_of_names = []
def delete_old_data():
for i in os.listdir("generated-certificates/"):
os.remove("generated-certificates/{}".format(i))
def cleanup_data():
with open('name-data.txt') as f:
for line in f:
list_of_names.append(line.strip())
def generate_certificates():
for index, name in enumerate(list_of_names):
certificate_template_image = cv2.imread("certificate-template.jpg")
cv2.putText(certificate_template_image,
name.strip(), (815,1500), cv2.FONT_HERSHEY_SIMPLEX,
5, (0, 0, 250), 5, cv2.LINE_AA)
cv2.imwrite("generated-certificates/{}.jpg".format(name.strip()), certificate_template_image)
print("Processing {} / {}".format(index + 1,len(list_of_names)))
def main():
delete_old_data()
cleanup_data()
generate_certificates()
if __name__ == '__main__':
main()
As can be seen, the Python script works, but everything is placed under a single script, from reading the information to generating certificates, and controlling the program flow, all at once. While it works perfectly, it can be difficult to manage as the program grows; the same goes for any other project.
For example, if we wish to modify the certificate layout, adjust the position of text, or change the data source from a text file to an Excel file, among other things, to do these, we would need to edit the same script. This increases the errors and makes the code longer and more complex than it should be, making it harder to debug, test, and maintain. This is where MVC comes in handy. By separating the data handling, the presentation, and lastly the program logic, the code becomes organized and ready for more scalable implementations.
Thus, this is how we can implement MVC using a new project structure
- Project Structure using MVC
certificate generator /
|
|--models/
| |--model.py
|
|--views/
| |--view.py
|
|--controllers/
| |--controller.py
|
|--run.py
|
|--name-data.txt
|
|--certificate-template.jpg
|
|--generated-certificates/
Next, we can now define the model, implement the view, and create the controller before putting it all together.
a. Define the Model
import cv2
import os
# receives list of names from controller and is responsible for rendering the certificates
def generate_certificates(list_of_names):
for index, name in enumerate(list_of_names):
certificate_template_image = cv2.imread("certificate-template.jpg")
cv2.putText(
certificate_template_image,
name,
(688,707), # customize position to move the text to your liking
cv2.FONT_HERSHEY_SIMPLEX,# customize font with another OpenCV font
5,# customize font size
(0, 0, 0), # customize color
5, # customize thickness
cv2.LINE_AA
)
cv2.imwrite(
os.path.join("generated-certificates", f"{name}.jpg"),
certificate_template_image
)
print(f"Processing {index + 1} / {len(list_of_names)}")
In this version, list_of_names is now used as a local variable, which enforces proper data flow.
b. Implement the View
import cv2
import os
# receives list of names from controller and is responsible for rendering the certificates
def generate_certificates(list_of_names):
for index, name in enumerate(list_of_names):
certificate_template_image = cv2.imread("certificate-template.jpg")
cv2.putText(
certificate_template_image,
name,
(688,707), # customize position to move the text to your liking
cv2.FONT_HERSHEY_SIMPLEX,# customize font with another OpenCV font
5,# customize font size
(0, 0, 0), # customize color
5, # customize thickness
cv2.LINE_AA
)
cv2.imwrite(
os.path.join("generated-certificates", f"{name}.jpg"),
certificate_template_image
)
print(f"Processing {index + 1} / {len(list_of_names)}")
Similar to model.py, we no longer depend on the global variable list_of_names. Instead, the function now receives data explicitly and no longer depends on external state.
You may also customize the input text to your liking from its position, font, font size, font color, and thickness. Feel free to explore and tweak as much as you can!
- How to identify the accurate position of your text
- Open your certificate template with MS Paint
- Point your cursor to the space you wish to fill with your text.
- Follow the coordinates found at the lower left.
c. Create the Controller
from models.model import delete_old_data, cleanup_data
from views.view import generate_certificates
def run_application():
delete_old_data()
list_of_names = cleanup_data()
generate_certificates(list_of_names)
Similar to the new versions of model.py and view.py, there is no global variable used anymore, and the data is passed explicitly. Making it a better design.
d. Putting it all together
from controllers.controller import run_application
if __name__ == "__main__":
run_application()
Acts as the entry point of the program.
An alternative is to use .xlsx files, which might be the most practical and efficient way, especially when handling a large number of recipients. This becomes particularly useful in events where information is often stored in spreadsheets.
To do this, we only have to modify model.py, a perfect scenario of why the separation of concerns is beneficial and how a well-structured architecture makes applications easier to maintain, extend, and eventually adapt to new changes.
- Modifying your data source
-
Install Pandas (if not yet installed)
py -m pip install pandas openpyxl -
Modify your model.py, assuming your Excel file looks like this
name date person1 date person2 date ... ... name-data.xlsx
-
Update models/model.py to this:
import os import pandas as pd def delete_old_data(): for i in os.listdir("generated-certificates/"): os.remove(os.path.join("generated-certificates/", i)) def cleanup_data(): # Read Excel file df = pd.read_excel("name-data.xlsx") # Convert each row into a dictionary records = df.to_dict(orient="records") return records
What changed?
✅ We added pandas
✅ We modified the cleanup_data function to read .xlsx, convert into a list of dictionaries -
Modify view.py as needed
import cv2 import os def generate_certificates(records): for index, record in enumerate(records): # used records (dictionary) certificate_template_image = cv2.imread("certificate-template.jpg") # dictionary key access name = str(record["name"]) date = str(record["date"]) # name cv2.putText( certificate_template_image, name, (688, 707), cv2.FONT_HERSHEY_SCRIPT_COMPLEX, 3, (0, 0, 0), 3, cv2.LINE_AA ) # date cv2.putText( certificate_template_image, date, (407, 1104), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 3, cv2.LINE_AA ) cv2.imwrite( os.path.join("generated-certificates", f"{name}.jpg"), certificate_template_image ) print(f"Processing {index + 1} / {len(records)}")
What changed?
✅ Used records instead of list_of_names
✅ Explicit string conversion is necessary for the use of OpenCV
✅ Accommodated additional information so that the view renders multiple pieces of informationThanks to the MVC-inspired structure, switching from a .txt file to an .xlsx file becomes less of a hassle with the help of the model that keeps data isolated from the rest, thus, preserving the rest of your application’s logic and layout.
Testing
- Testing with txt files
- Simply run the program in your terminal with
python run.py
or
py run.py
And let’s say you have 10 recipients of your certificate.
Check the generated-certificates folder, and it should contain all of the certificates of the recipients.
- Testing with xlsx file
- Follow the same steps, and it should produce the same set of certificates, but this time, with date included.
How MVC Made the Project Clear
Using MVC made the project much easier to understand, manage, and maintain. By separating the system into three parts: one handles the data such as the recipient’s name, date, and event details, another part controls the certificate layout and design—how it looks on the screen, and another part manages the user’s actions and ties everything together. Because of the clear separation of roles between them, the system considerably becomes easier to maintain and manage.
While this is a clean, beginner-friendly, MVC-inspired modular architecture, its implementation does not represent a full framework-level MVC with reactive views or even user-driven controllers. Yet, this project applies the very core principle of MVC, which is the separation of concerns. By dividing its data handling, presentation logic, and program control into separate modules, the project becomes more modular, maintainable, and scalable.
Furthermore, debugging became simpler as separation of components means the errors are confined to specific components rather than affecting the entire system. That’s why MVC makes it easier to scale and improve projects in the future.
Hmm, what could possibly go wrong if you put all of your eggs in one basket? 🤔
Not applying MVC would mean that all of the components are in one place; code for interface, logic, and data handling is mixed together. This would signify that in the case of an error, the entire system could be affected, making debugging more difficult. Additionally, making changes in one part of the code would be difficult, as doing so might unintentionally break other parts. This makes the system harder to scale or expand. Without MVC, every part of the code might need adjustments. That would be very tiring…😔
Conclusion
By applying MVC in building an automated certificate generator using python, it ensures that the project will be maintainable, reusable, and easy to scale and expand in the future.
Remember not to put all of your eggs in one basket! 🥚✨
It’s a wrap!🎉 Now you know that understanding MVC would not only help developers structure projects cleanly, but also lay the foundation for advanced design patterns such as MVVM and MVP, which are all principles adopted in clean architecture to create maintainable and scalable software.
So, don’t stop here. Challenge yourself to go beyond the basics—feel free to customize it further, you can enhance it by adding GUI or even deploying it as a web application. Keep innovating, keep refining, and keep learning! 🌟
Happy building! 🚀
References
https://www.codecademy.com/article/mvc-architecture-model-view-controller







Top comments (0)