Итак, у меня есть приложение, написанное на nodejs.В настоящее время, когда я создаю проблему, а затем редактирую ту же самую проблему, title_name и описание, название заголовка обновляется и отображается во внешнем интерфейсе, однако описание остается тем же и не обновляется.Я просматривал мой код на python и таблицу sql, но это выглядит хорошо, даже мой файл index.js.Он запустит оператор update для заголовка и обновит его, однако для описания он не будет.Пока у меня есть следующее:
Мои resources.py:
class IssueResource(object):
def __init__(self, repo):
self._repo = repo
def on_get(self, req, resp, issue_id):
with self._repo.open() as repo:
issue = repo.issues.fetch_issue(int(issue_id))
resp.media = _issue_to_json(issue)
resp.status = falcon.HTTP_200
def on_put(self, req, resp, issue_id):
with self._repo.open() as repo:
update = req.media
repo.issues.update_issue(issue_id, **update)
resp.status = falcon.HTTP_204
models.py
def fetch_issue(self, issue_id):
cursor = self._conn.cursor()
try:
cursor.execute(
"""SELECT
id,
title,
description,
opened_datetime,
closed_datetime
FROM issues
WHERE id = {}""".format(issue_id))
return make_issue(cursor.fetchone())
finally:
cursor.close()
def update_issue(self, issue_id, **kwargs):
cursor = self._conn.cursor()
try:
if 'title' in kwargs:
cursor.execute(
"""UPDATE issues SET title = '{}' WHERE id = {}"""
.format(kwargs['title'], issue_id)
)
if 'description' in kwargs:
cursor.execute(
"""UPDATE issues SET description = '{}' WHERE id = {}"""
.format(kwargs['description'], issue_id)
)
if 'closed' in kwargs:
cursor.execute(
"""UPDATE issues SET closed_datetime = '{}' WHERE id = {}"""
.format(kwargs['closed'].isoformat(), issue_id)
)
finally:
cursor.close()
Это структура моей таблицы sql:
CREATE TABLE issues(
id INTEGER PRIMARY KEY,
title VARCHAR(255),
description TEXT,
opened_datetime CHAR(26) DEFAULT (datetime('now')),
closed_datetime CHAR(26)
)
Мой внешний интерфейс моего приложения выглядит следующим образом: index.js - это то место, где установлена вся моя маршрутизация:
require('babel-polyfill')
const m = require('mithril')
const {IssuesList, ViewIssue, CreateIssue, EditIssue, ToolbarContainer} = require('./views')
const {IssuesModel} = require('./viewmodels')
const issuesModel = new IssuesModel()
m.route(document.body, '/issues', {
'/issues': {
render(vnode) {
return m(ToolbarContainer, m(IssuesList, {model: issuesModel}))
}
},
'/issues/create': {
render(vnode) {
return m(ToolbarContainer, m(CreateIssue, {model: issuesModel}))
}
},
'/issues/:issueId/edit': {
render(vnode) {
return m(ToolbarContainer, m(EditIssue, {model: issuesModel, issueId: vnode.attrs.issueId}))
}
}
})
view.js - это все представления каждогодругая страница:
const m = require('mithril')
class IssuesList {
constructor(vnode) {
this.model = vnode.attrs.model
}
oninit() {
this.model.loadIssues()
}
view() {
return m('table.table', [
m('thead', [
m('th', 'title'),
m('th', 'opened'),
m('th', 'closed')
]),
m('tbody', [
this.model.list.map(item =>
m('tr', [
m('td.title-cell', m("a", {href: `/issues/${item.id}`, oncreate: m.route.link}, item.title)),
m('td.opened-cell', item.opened),
m('td.closed-cell', item.closed)
])
)
])
])
}
}
class ViewIssue {
constructor(vnode) {
this.model = vnode.attrs.model
this.issueId = vnode.attrs.issueId
}
oninit() {
this.model.loadIssue(this.issueId)
}
view() {
let detail = this.model.issues[this.issueId]
return detail
? m('div',[
m('.row', [
m('h1.col-sm-11', detail.title),
m('.col-sm-1',
m(
'a.btn.btn-primary',
{href: `/issues/${this.issueId}/edit`, oncreate: m.route.link},
'Edit'
)
)
]),
m('dl.row', [
m('dt.col-sm-3', 'Opened'),
m('dd.col-sm-3', detail.opened),
m('dt.col-sm-3', 'Closed'),
m('dd.col-sm-3', detail.closed),
]),
m('h2', 'Description'),
m('p.description', detail.description)
]
)
: m('.alert.alert-info', 'Loading')
}
}
class EditIssue {
constructor(vnode) {
this.model = vnode.attrs.model
this.issueId = vnode.attrs.issueId
}
async oninit() {
await this.model.loadIssue(this.issueId)
}
view() {
let issue = this.model.issues[this.issueId]
return issue
? m(IssueEditor, {
title: issue.title,
descriptionText: issue.description,
onSubmit: async (fields) => {
await this.model.updateIssue(this.issueId, fields)
m.route.set(`/issues/${this.issueId}`)
m.redraw()
}
})
:m('.alert.alert-info', 'Loading')
}
}
class CreateIssue {
constructor(vnode) {
this.model = vnode.attrs.model
}
view() {
return m(IssueEditor, {
title: '',
descriptionText: '',
onSubmit: async ({descriptionText, title}) => {
await this.model.createIssue({description: descriptionText, title: title})
m.route.set(`/issues`)
m.redraw()
}
})
}
}
class IssueEditor {
constructor(vnode) {
this.title = vnode.attrs.title
this.descriptionText = vnode.attrs.descriptionText
this.onSubmit = vnode.attrs.onSubmit
}
view() {
return m('form', {onsubmit: e => this.onSubmit({title: this.title, descriptionText: this.descriptionText})}, [
m('.form-group', [
m('label', {'for': 'title-input'}, 'Issue Title'),
m('input.form-control#title-input', {value: this.title, oninput: (e) => {this.title = e.target.value}})
]),
m('.form-group', [
m('label', {'for': 'description-input'}, 'Description'),
m('textarea.form-control#description-input', {oninput: (e) => {this.descriptionText = e.target.value}}, this.descriptionText)
]),
m('button.btn.btn-primary#save-button', {type: 'submit'}, 'Save')
])
}
}
module.exports = {IssuesList, ViewIssue, EditIssue, CreateIssue, IssueEditor}
Основной скрипт для запуска приложения python:
from __future__ import absolute_import
import argparse
import falcon
import os
from .resources import IssueResource, IssuesResource
from .models import Repository
def _index_middleware(app):
def handler(environ, start_response):
if environ['PATH_INFO'] == '/':
environ['PATH_INFO'] = '/index.html'
return app(environ, start_response)
return handler
def make_api(database_location, migrate_database=True):
api = falcon.API()
repo = Repository(database_location)
if migrate_database:
repo.migrate_database()
api.add_route('/issues', IssuesResource(repo))
api.add_route('/issues/{issue_id}', IssueResource(repo))
static_dir = os.path.abspath(os.path.join(__file__, '..', '..', 'dist'))
api.add_static_route('/', static_dir)
return _index_middleware(api)
if __name__ == '__main__':
from werkzeug.serving import make_server
parser = argparse.ArgumentParser(description="Run a bug tracker server")
parser.add_argument('--interface', default='0.0.0.0',
help="Interface to bind to")
parser.add_argument('--port', default=8640,
help="Port to listen on")
parser.add_argument('--database-location',
default=os.path.join(
os.path.dirname(__file__), '..', 'database.db'
), help="Where to store the database")
parser.add_argument('--no-database-migrations', action='store_true',
help="Do not perform database migrations")
parser.add_argument('--clean', action='store_true',
help="Delete the database and start from clean")
args = parser.parse_args()
if args.clean:
os.remove(args.database_location)
api = make_api(args.database_location, not args.no_database_migrations)
httpd = make_server(args.interface, args.port, api)
print "Serving on {args.interface}:{args.port}".format(args=args)
httpd.serve_forever()