3
\$\begingroup\$

I'm using Flask along with Flask-SQLAlchemy and Flask-WTF.

I have a model:

class Trip(db.Model):
    id = db.Column(db.BigInteger, primary_key=True)
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'), index=True,
                          nullable=False)
    name = db.Column(db.String(2000), nullable=False)
    country_code = db.Column(db.String(2))
    slug = db.Column(db.String(2000), nullable=False)

    author = db.relationship('User',
                             backref=db.backref('trips',
                                                order_by=lambda: Trip.name))

    def __repr__(self):
        return f"<Trip {self.id} author_id={self.author_id} slug={self.slug}>"


db.Index('idx_trip_author_slug', Trip.author_id, Trip.slug, unique=True)

To create and update trips, I use class-based views like this:

class TripCUView(MethodView):
    methods = ('GET', 'POST')
    decorators = [user_required]
    title = 'Trip action'
    submit_text = 'Save'

    def dispatch_request(self, *args, **kwargs):
        self.model = self._instant_model()
        return super().dispatch_request(*args, **kwargs)

    def get(self):
        self.form = self._build_form()
        return self._default_render()

    def post(self):
        self.form = TripForm()
        if self.form.validate():
            try:
                self.form.populate_obj(self.model)
                db.session.add(self.model)
                db.session.commit()
                return redirect(url_for('.index'))
            except IntegrityError as e:
                db.session.rollback()
                if (e.orig.pgcode == pgerrorcodes.UNIQUE_VIOLATION):
                    self.form.errors.setdefault('slug', [])
                    self.form.errors['slug'].append('Already exists')
                    return self._default_render()
                else:
                    raise e
        return self._default_render()

    def _build_form(self):
        raise NotImplementedError

    def _instant_model(self) -> Trip:
        raise NotImplementedError

    def _default_render(self):
        return render_template('form.html', form=self.form,
                               title=self.title,
                               submit_text=self.submit_text)


class CreateTripView(TripCUView):
    title = 'Create trip'

    def _build_form(self):
        return TripForm()

    def _instant_model(self):
        return Trip(author=g.user)


class UpdateTripView(TripCUView):
    @property
    def title(self):
        return f"Updating {self.model.name}"

    def dispatch_request(self, slug):
        self.slug = slug
        return super().dispatch_request()

    def _build_form(self):
        return TripForm(obj=self.model)

    def _instant_model(self):
        return Trip.query\
                   .filter_by(slug=self.slug, author=g.user)\
                   .first_or_404()


trips.add_url_rule('/new', view_func=CreateTripView.as_view('new'))
trips.add_url_rule('/<slug>/update',
                   view_func=UpdateTripView.as_view('update'))

Basically, I override the post method on my MethodView subclass to check for integrity errors and translate them into form errors if they are indeed uniqueness violations.

Can it be done better?

\$\endgroup\$
  • \$\begingroup\$ I think Marshmallow could help you to validate any kind of input from the user using Model validation and normal input validation as well as output sanatization. marshmallow \$\endgroup\$ – MasterOfTheHouse Jan 31 at 4:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.