Skip to content

liaaana/flask-planner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Flask Planner

Web-based planning application


Web application in which you can add, modify, delete and mark tasks as completed. Tasks that have a specific date can be seen in the calendar.

It is also possible to create categories and assign tasks to them. Categories can be changed and removed with or without removal of all the tasks included in this category.

Made with the Flask framework in Python language

Installation and launching

# make sure that you are in the project folder
pip install requirements.txt 
python3 main.py 

Example of creating a "add_task" function.

1. Creating a task model, where you specify what parameters each task has.

import sqlalchemy
from sqlalchemy import orm
from sqlalchemy_serializer import SerializerMixin
from .db_session import SqlAlchemyBase


class Task(SqlAlchemyBase, SerializerMixin):
    __tablename__ = 'tasks'
    id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, autoincrement=True)
    title = sqlalchemy.Column(sqlalchemy.String, nullable=True)
    content = sqlalchemy.Column(sqlalchemy.String, nullable=True)
    date = sqlalchemy.Column(sqlalchemy.DateTime, default=None)
    start_time = sqlalchemy.Column(sqlalchemy.Time, default=None)
    end_time = sqlalchemy.Column(sqlalchemy.Time, default=None)
    is_done = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
    user_id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("users.id"))
    category_id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey("categories.id"))
    user = orm.relation('User')
    category = orm.relation('Category')

2. Next, the creation of a form, through which the user can add his tasks.

from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField
from wtforms import BooleanField, SubmitField, DateField, RadioField, TimeField
from wtforms.validators import DataRequired, Length, InputRequired, Optional
from wtforms.widgets import TimeInput, DateInput


class TaskForm(FlaskForm):
    title = StringField('Заголовок', validators=[DataRequired()],
                        render_kw={"placeholder": 'Заголовок'})
    content = TextAreaField("Содержание", render_kw={"placeholder": 'Содержание'})
    date = DateField('Дата', widget=DateInput(), validators=[Optional()])
    start_time = TimeField('Время начала', widget=TimeInput(), validators=[Optional()])
    end_time = TimeField('Время окончания', widget=TimeInput(), validators=[Optional()])
    category = RadioField('Категория', default=1)
    submit = SubmitField('Готово')

3. Using the basic template "base.html", we create an html page with which the user will interact.

{% extends "base.html" %}

{% block style %}
<link rel="stylesheet" href="../static/css/task_add_style.css">
{% endblock %}

{% block content %}
<div class="add_task">
<h2>{{ title }}</h2>
<form action="" method="post">
    {{ form.hidden_tag() }}
    <p>
        {{ form.title(class="form-control") }}<br>
        {% for error in form.title.errors %}
            <p class="alert alert-danger" role="alert">
                {{ error }}
            </p>
        {% endfor %}
    </p>
    <p>
        {{ form.content(class="form-control") }}<br>
        {% for error in form.content.errors %}
            <p class="alert alert-danger" role="alert">
                {{ error }}
            </p>
        {% endfor %}
    </p>
    <p>
        {{ form.date(class="form-control") }}<br>
        {% for error in form.date.errors %}
        <p class="alert alert-danger" role="alert">
            {{ error }}
        </p>
        {% endfor %}
    </p>
    <p>
        {{ form.start_time(class="form-control") }}<br>
        {% for error in form.start_time.errors %}
        <p class="alert alert-danger" role="alert">
            {{ error }}
        </p>
        {% endfor %}
    </p>
    <p>
        {{ form.end_time(class="form-control") }}<br>
        {% for error in form.end_time.errors %}
        <p class="alert alert-danger" role="alert">
            {{ error }}
        </p>
        {% endfor %}
    </p>
    <p>
        <div class='form_radio_group'>
        {% for i, ctg in form.category.choices %}
        <div class="form_radio_group-item">
            {% if ctg.id == form.category.default %}
            <input checked id={{ctg.id}}  name="category" type="radio" value={{ ctg.id }}>
            {% else %}
            <input id={{ctg.id}}  name="category" type="radio" value={{ ctg.id }}>
            {% endif %}
            <label for={{ctg.id}}>{{ ctg.name }}</label>
        </div>
        {% endfor %}
        </div>
        {% for error in form.category.errors %}
        <p class="alert alert-danger" role="alert">
            {{ error }}
        </p>
        {% endfor %}
    </p>
    <p>{{ form.submit(type="submit", class="button") }}</p>
    <p class='message'>{{message}}</p>
</form>
</div>
{% endblock %}

4. As the last step, we connect the html page to the address '.../task_add' in main.py. The same function detects errors, takes the user back and tells him what needs to be fixed.

@app.route('/task_add', methods=['GET', 'POST']) # добавление задачи
@login_required
def add_task():
    form = TaskForm()
    db_sess = db_session.create_session()
    categories = db_sess.query(Category).filter(Category.user_id == current_user.id).all()
    form.category.choices = [(i.id, i) for i in categories]
    form.category.default = [i for i in categories if i.name == 'Без категории'][0].id
    if form.validate_on_submit():
        if request.form.get('category') is None:
            return render_template('task_add.html',
                                   title='Добавление задачи',
                                   form=form,
                                   message='Необходимо выбрать категорию',
                                   date=datetime.datetime.now())
        elif form.date.data is not None and form.date.data < datetime.date.today():
            form.category.default = int(request.form.get('category'))
            return render_template('task_add.html',
                                   title='Добавление задачи',
                                   form=form,
                                   message='Выбрана дата из прошлого',
                                   date=datetime.datetime.now())
        elif form.start_time.data is not None and form.end_time.data is not None and form.start_time.data > form.end_time.data:
            form.category.default = int(request.form.get('category'))
            return render_template('task_add.html',
                                   title='Добавление задачи',
                                   form=form,
                                   message='Время начала позже времени окончания',
                                   date=datetime.datetime.now())
        elif form.start_time.data is not None and form.end_time.data is None:
            form.category.default = int(request.form.get('category'))
            return render_template('task_add.html',
                                   title='Добавление задачи',
                                   form=form,
                                   message='Добавьте время окончания',
                                   date=datetime.datetime.now())
        elif form.start_time.data is None and form.end_time.data is not None:
            form.category.default = int(request.form.get('category'))
            return render_template('task_add.html',
                                   title='Добавление задачи',
                                   form=form,
                                   message='Время начала позже времени окончания',
                                   date=datetime.datetime.now())
        elif len(form.title.data) > 100 or len(form.title.data) < 1:
            form.category.default = int(request.form.get('category'))
            return render_template('task_add.html',
                                   title='Добавление задачи',
                                   form=form,
                                   message='Заголовок задачи должен быть от 1 до 100 символов',
                                   date=datetime.datetime.now())
        task = Task()
        task.title = form.title.data
        task.content = form.content.data
        task.date = form.date.data
        task.start_time = form.start_time.data
        task.end_time = form.end_time.data
        task.category_id = int(request.form.get('category'))
        current_user.tasks.append(task)
        db_sess.merge(current_user)
        db_sess.commit()
        return redirect('/tasks')
    return render_template('task_add.html',
                           title='Добавление задачи',
                           form=form,
                           date=datetime.datetime.now())

Several challenges

Problem Solution
Registration and authorization take place on one page, and it is impossible to connect 2 functions to one page Create 2 different forms and perform processing depending on the form sent.
Each task should have a category, but when a user tries to create the first task, it may not have any category Automatically create a category when a new user is added
In this project I put into practice the knowledge of the course flask but I wanted to have a beautiful design I used designs from public sources and YouTube tutorials

All functions

  • login_register
  • tasks
  • add_task
  • edit_task
  • task_delete
  • tasks_calendar
  • categories
  • add_category
  • edit_category
  • category_delete (without deleting tasks in this category)
  • category_delete_with_tasks

Some more gifs

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published