Редактирование данных

Последнее обновление: 03.03.2018

Продолжим работу с проектом из прошлой темы и добавим в него возможность редактирования данных.

Редактирование данных, как и добавление, разбивается на две части. Вначале нам надо отобразить пользователю форму для изменения выбранного объекта. Потом нам надо получить отправленные данные и сохранить их в базу данных.

Прежде всего определим форму для редактирования. Для этого в папке templates создадим файл edit.html.

Edit data in Golang

Определим в файле edit.html следующий код:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Edt Product</title>
    </head>
    <body>
        <h3>Edit Product</h3>
        <form method="POST">
            <input type="hidden" name="id" value="{{.Id}}" />
            <label>Model</label><br>
            <input type="text" name="model" value="{{.Model}}" /><br><br>
            <label>Company</label><br>
            <input type="text" name="company" value="{{.Company}}" /><br><br>
            <label>Price</label><br>
            <input type="number" name="price" value="{{.Price}}" /><br><br>
            <input type="submit" value="Send" />
        </form>
    </body>
</html>

Данный файл представляет шаблон, в который из кода сервера будут передаваться редактируемые данные.

Теперь изменим код сервера, добавив в него возможность редактирования:

package main
import (
    "fmt"
	"database/sql"
    _ "github.com/go-sql-driver/mysql"
	"net/http"
	"html/template"
	"log"
	"github.com/gorilla/mux"
)
type Product struct{
    Id int
    Model string
    Company string
    Price int
}
var database *sql.DB

// возвращаем пользователю страницу для редактирования объекта
func EditPage(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
    id := vars["id"]

	row := database.QueryRow("select * from productdb.Products where id = ?", id)
	prod := Product{}
	err := row.Scan(&prod.Id, &prod.Model, &prod.Company, &prod.Price)
    if err != nil{
		log.Println(err)
		http.Error(w, http.StatusText(404), http.StatusNotFound)
	}else{
		tmpl, _ := template.ParseFiles("templates/edit.html")
		tmpl.Execute(w, prod)
	}
}
// получаем измененные данные и сохраняем их в БД
func EditHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		log.Println(err)
	}
	id := r.FormValue("id")
	model := r.FormValue("model")
	company := r.FormValue("company")
	price := r.FormValue("price")

	_, err = database.Exec("update productdb.Products set model=?, company=?, price = ? where id = ?", 
		model, company, price, id)

	if err != nil {
		log.Println(err)
	}
	http.Redirect(w, r, "/", 301)
}

func CreateHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {

		err := r.ParseForm()
		if err != nil {
			log.Println(err)
		}
  		model := r.FormValue("model")
  		company := r.FormValue("company")
  		price := r.FormValue("price")

  		_, err = database.Exec("insert into productdb.Products (model, company, price) values (?, ?, ?)", 
		  model, company, price)

  		if err != nil {
    		log.Println(err)
		}
		http.Redirect(w, r, "/", 301)
	}else{
		http.ServeFile(w,r, "templates/create.html")
	}
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {

	rows, err := database.Query("select * from productdb.Products")
	if err != nil {
		log.Println(err)
	}
	defer rows.Close()
	products := []Product{}
	
	for rows.Next(){
		p := Product{}
		err := rows.Scan(&p.Id, &p.Model, &p.Company, &p.Price)
		if err != nil{
			fmt.Println(err)
			continue
		}
		products = append(products, p)
	}

	tmpl, _ := template.ParseFiles("templates/index.html")
	tmpl.Execute(w, products)
}

func main() {
	 
	db, err := sql.Open("mysql", "root:password@/productdb")
    
    if err != nil {
        log.Println(err)
	}
	database = db
	defer db.Close()
	
	router := mux.NewRouter()
	router.HandleFunc("/", IndexHandler)
  	router.HandleFunc("/create", CreateHandler)
    router.HandleFunc("/edit/{id:[0-9]+}", EditPage).Methods("GET")
	router.HandleFunc("/edit/{id:[0-9]+}", EditHandler).Methods("POST")
	
    http.Handle("/",router)

	fmt.Println("Server is listening...")
	http.ListenAndServe(":8181", nil)
}

По сравнению с прошлой темой здесь добавлены функции EditPage и EditHandler и изменена функция main.

Чтобы указать, какой объект будет редактироваться, мы будем передавать через адрес id этого объекта. И для упрощения маршрутизации в данном случае мы будем использовать пакет gorilla/mux.

В функции IndexPage мы получаем id объекта, который надо изменить, извлекаем из БД даные этого объекта и передаем их в шаблон edit.html:

func EditPage(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
    id := vars["id"]

	row := database.QueryRow("select * from productdb.Products where id = ?", id)
	prod := Product{}
	err := row.Scan(&prod.Id, &prod.Model, &prod.Company, &prod.Price)
    if err != nil{
		log.Println(err)
		http.Error(w, http.StatusText(404), http.StatusNotFound)
	}else{
		tmpl, _ := template.ParseFiles("templates/edit.html")
		tmpl.Execute(w, prod)
	}
}

На случай, если в базе данных не окажется объекта с подобным id, с помощью функции http.Error() возвращаем статусный код 404, который указывает, что объект не найден.

В функции EditHandler получаем данные из отправленной формы и с их помощью изменяем объект в базе данных по определенному id.

func EditHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		log.Println(err)
	}
	id := r.FormValue("id")
	model := r.FormValue("model")
	company := r.FormValue("company")
	price := r.FormValue("price")

	_, err = database.Exec("update productdb.Products set model=?, company=?, price = ? where id = ?", 
		model, company, price, id)

	if err != nil {
		log.Println(err)
	}
	http.Redirect(w, r, "/", 301)
}

После обновления БД выполняется редирект на главную страницу.

В функции main эти функции EditPage и EditHandler связываются с определенными маршрутами. По сути они привязаны к одному и тому же маршруту, однако для разного типа запросов: EditPage для запросов GET, а EditHandler - для запросов POST.

router.HandleFunc("/edit/{id:[0-9]+}", EditPage).Methods("GET")
router.HandleFunc("/edit/{id:[0-9]+}", EditHandler).Methods("POST")

Стоит отметить, что добавление данных, которое представлено в данном случае функцией CreateHandler, также фактически выполняет два действия в зависимости от типа запроса: отображает страницу для добавления и собственно добавляет данные. И в прицнипе организацию добавления можно сделать также, как и редактирование, разделив на две функции для каждого типа запросов.

Для упрощения управлением объектами изменим файл index.html, добавив в него ссылки на редактирование:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Products</title>
    </head>
    <body>
        <h2>Список товаров</h2>
        <p><a href="/create">Добавить</a></p>
        <table>
            <thead><th>Id</th><th>Model</th><th>Company</th><th>Price</th><th></th></thead>
            {{range . }}
            <tr>
                <td>{{.Id}}</td>
                <td>{{.Model}}</td>
                <td>{{.Company}}</td>
                <td>{{.Price}}</td>
                <td><a href="/edit/{{.Id}}">Изменить</a>
                </td>
            </tr>
            {{end}}
        </table>
    </body>
</html>

И после запуска приложения мы сможем отредактировать нужные объекты:

Редактирование данных в БД в Go
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850