List posts with pagination
This commit is contained in:
parent
fcacae04b8
commit
2e8016d23c
@ -1 +1,3 @@
|
|||||||
|
HOST=127.0.0.1
|
||||||
|
PORT=5000
|
||||||
DATABASE_URL="mysql://root:@localhost/rocket_example"
|
DATABASE_URL="mysql://root:@localhost/rocket_example"
|
||||||
|
@ -17,6 +17,7 @@ actix-web = "3"
|
|||||||
actix-files = "0.5"
|
actix-files = "0.5"
|
||||||
tera = "1.8.0"
|
tera = "1.8.0"
|
||||||
dotenv = "0.15"
|
dotenv = "0.15"
|
||||||
|
listenfd = "0.3.3"
|
||||||
|
|
||||||
# remove `path = ""` in your own project
|
# remove `path = ""` in your own project
|
||||||
sea-orm = { path = "../../", version = "^0.2", features = [
|
sea-orm = { path = "../../", version = "^0.2", features = [
|
||||||
|
@ -1 +1,8 @@
|
|||||||
# Actix with SeaORM example app
|
# Actix with SeaORM example app
|
||||||
|
|
||||||
|
Rus server with auto-reloading:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo install systemfd
|
||||||
|
systemfd --no-pid -s http::5000 -- cargo watch -x run
|
||||||
|
```
|
||||||
|
@ -5,37 +5,56 @@ use actix_http::{body::Body, Response};
|
|||||||
use actix_web::dev::ServiceResponse;
|
use actix_web::dev::ServiceResponse;
|
||||||
use actix_web::http::StatusCode;
|
use actix_web::http::StatusCode;
|
||||||
use actix_web::middleware::errhandlers::{ErrorHandlerResponse, ErrorHandlers};
|
use actix_web::middleware::errhandlers::{ErrorHandlerResponse, ErrorHandlers};
|
||||||
use actix_web::{error, get, middleware, post, web, App, Error, HttpResponse, HttpServer, Result};
|
use actix_web::{
|
||||||
|
error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result,
|
||||||
|
};
|
||||||
|
use listenfd::ListenFd;
|
||||||
|
use sea_orm::query::*;
|
||||||
|
use sea_orm::DatabaseConnection;
|
||||||
|
use sea_orm::EntityTrait;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::env;
|
||||||
use tera::Tera;
|
use tera::Tera;
|
||||||
|
|
||||||
mod post;
|
mod post;
|
||||||
pub use post::Entity as Post;
|
pub use post::Entity as Post;
|
||||||
use sea_orm::query::*;
|
|
||||||
use sea_orm::DatabaseConnection;
|
|
||||||
use sea_orm::EntityTrait;
|
|
||||||
|
|
||||||
mod setup;
|
mod setup;
|
||||||
|
|
||||||
|
const DEFAULT_POSTS_PER_PAGE: usize = 4;
|
||||||
|
|
||||||
struct AppState {
|
struct AppState {
|
||||||
db_url: String,
|
db_url: String,
|
||||||
templates: tera::Tera,
|
templates: tera::Tera,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct Params {
|
||||||
|
page: Option<usize>,
|
||||||
|
posts_per_page: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
async fn list(data: web::Data<AppState>) -> Result<HttpResponse, Error> {
|
async fn list(req: HttpRequest, data: web::Data<AppState>) -> Result<HttpResponse, Error> {
|
||||||
let template = &data.templates;
|
let template = &data.templates;
|
||||||
let conn = sea_orm::Database::connect(&data.db_url).await.unwrap();
|
let conn = sea_orm::Database::connect(&data.db_url).await.unwrap();
|
||||||
|
|
||||||
let posts = Post::find()
|
// get params
|
||||||
.all(&conn)
|
let params = web::Query::<Params>::from_query(req.query_string()).unwrap();
|
||||||
|
|
||||||
|
let page = params.page.unwrap_or(0);
|
||||||
|
let posts_per_page = params.posts_per_page.unwrap_or(DEFAULT_POSTS_PER_PAGE);
|
||||||
|
let paginator = Post::find().paginate(&conn, posts_per_page);
|
||||||
|
let num_pages = paginator.num_pages().await.ok().unwrap();
|
||||||
|
|
||||||
|
let posts = paginator
|
||||||
|
.fetch_page(page)
|
||||||
.await
|
.await
|
||||||
.expect("could not retrieve posts");
|
.expect("could not retrieve posts");
|
||||||
|
|
||||||
let mut ctx = tera::Context::new();
|
let mut ctx = tera::Context::new();
|
||||||
ctx.insert("posts", &posts);
|
ctx.insert("posts", &posts);
|
||||||
ctx.insert("page", &0);
|
ctx.insert("page", &page);
|
||||||
ctx.insert("num_pages", &1);
|
ctx.insert("posts_per_page", &posts_per_page);
|
||||||
|
ctx.insert("num_pages", &num_pages);
|
||||||
|
|
||||||
let body = template
|
let body = template
|
||||||
.render("index.html.tera", &ctx)
|
.render("index.html.tera", &ctx)
|
||||||
@ -47,12 +66,20 @@ async fn list(data: web::Data<AppState>) -> Result<HttpResponse, Error> {
|
|||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
std::env::set_var("RUST_LOG", "actix_web=info");
|
std::env::set_var("RUST_LOG", "actix_web=info");
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
let db_url = "mysql://root:@localhost/rocket_example";
|
|
||||||
|
// get env vars
|
||||||
|
dotenv::dotenv().ok();
|
||||||
|
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set in .env file");
|
||||||
|
let host = env::var("HOST").expect("HOST is not set in .env file");
|
||||||
|
let port = env::var("PORT").expect("PORT is not set in .env file");
|
||||||
|
let server_url = format!("{}:{}", host, port);
|
||||||
|
|
||||||
|
// create post table if not exists
|
||||||
let conn = sea_orm::Database::connect(&db_url).await.unwrap();
|
let conn = sea_orm::Database::connect(&db_url).await.unwrap();
|
||||||
let _ = setup::create_post_table(&conn).await;
|
let _ = setup::create_post_table(&conn).await;
|
||||||
|
|
||||||
println!("Listening on: 127.0.0.1:8080");
|
let mut listenfd = ListenFd::from_env();
|
||||||
HttpServer::new(move || {
|
let mut server = HttpServer::new(move || {
|
||||||
let templates = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
|
let templates = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
|
||||||
App::new()
|
App::new()
|
||||||
.data(AppState {
|
.data(AppState {
|
||||||
@ -61,14 +88,20 @@ async fn main() -> std::io::Result<()> {
|
|||||||
})
|
})
|
||||||
.wrap(middleware::Logger::default()) // enable logger
|
.wrap(middleware::Logger::default()) // enable logger
|
||||||
.service(fs::Files::new("/static", "./static").show_files_listing())
|
.service(fs::Files::new("/static", "./static").show_files_listing())
|
||||||
.configure(init) // init todo routes
|
.configure(init)
|
||||||
})
|
});
|
||||||
.bind("127.0.0.1:8080")?
|
|
||||||
.run()
|
server = match listenfd.take_tcp_listener(0)? {
|
||||||
.await
|
Some(listener) => server.listen(listener)?,
|
||||||
|
None => server.bind(&server_url)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Starting server at {}", server_url);
|
||||||
|
server.run().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// function that will be called on new Application to configure routes for this module
|
|
||||||
pub fn init(cfg: &mut web::ServiceConfig) {
|
pub fn init(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(list);
|
cfg.service(list);
|
||||||
}
|
}
|
||||||
|
@ -48,9 +48,15 @@
|
|||||||
<td></td>
|
<td></td>
|
||||||
<td>
|
<td>
|
||||||
{% if page == 0 %} Previous {% else %}
|
{% if page == 0 %} Previous {% else %}
|
||||||
<a href="/?page={{ page - 1 }}">Previous</a>
|
<a
|
||||||
|
href="/?page={{ page - 1 }}&posts_per_page={{ posts_per_page }}"
|
||||||
|
>Previous</a
|
||||||
|
>
|
||||||
{% endif %} | {% if page == num_pages - 1 %} Next {% else %}
|
{% endif %} | {% if page == num_pages - 1 %} Next {% else %}
|
||||||
<a href="/?page={{ page + 1 }}">Next</a>
|
<a
|
||||||
|
href="/?page={{ page + 1 }}&posts_per_page={{ posts_per_page }}"
|
||||||
|
>Next</a
|
||||||
|
>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user