Skip to content

Image upload #5075

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
AnonimPython opened this issue Apr 1, 2025 · 6 comments
Open

Image upload #5075

AnonimPython opened this issue Apr 1, 2025 · 6 comments

Comments

@AnonimPython
Copy link

AnonimPython commented Apr 1, 2025

Hi Developers!

I have a problem with upload for pictures
reflex does not have dynamic page reload. When a file with a photo is placed and saved in the database, it is dynamically added to the bottom of the page (for testing) and I noticed that when you add pictures, they are not displayed on the screen. But when you reload the server - everything is there. Agree, this is not convenient to add a gallery - you need to reload the page, which is not very convenient, especially if the project is already in operation.
Tell me where my mistakes are?

Code:

from datetime import datetime
from sqlmodel import select, Field
from typing import Optional
import uuid


class Image(rx.Model, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    filename: str = Field(max_length=255)
    caption: str = Field(max_length=500)
    path: str = Field(max_length=255)
    created_at: datetime = Field(default_factory=datetime.utcnow)

class State(rx.State):
    """The app state."""
    images: list[Image] = []
    caption: str = ""
    processing: bool = False
    progress: int = 0
    
    def on_load(self):
        """Load existing images on page load."""
        with rx.session() as session:
            self.images = session.exec(
                select(Image).order_by(Image.created_at.desc())
            ).all()

    @rx.event
    async def handle_upload_progress(self, progress: dict):
        """Handle upload progress updates."""
        self.processing = True
        self.progress = round(progress["progress"] * 100)
        if self.progress >= 100:
            self.processing = False
            self.on_load()

    @rx.event
    async def handle_upload(self, files: list[rx.UploadFile]):
        if not files or not self.caption:
            return rx.window_alert("Please, add a caption for image")
        
        for file in files:
            file_extension = file.name.split('.')[-1]
            unique_filename = f"{uuid.uuid4()}.{file_extension}"
            
            
            upload_dir = rx.get_upload_dir()
            outfile = upload_dir / unique_filename
            
            
            upload_data = await file.read()
            with outfile.open("wb") as file_object:
                file_object.write(upload_data)

            try:
                file_url = f"/_upload/{unique_filename}"
                
                with rx.session() as session:
                    db_image = Image(
                        filename=unique_filename,
                        caption=self.caption,
                        path=file_url 
                    )
                    session.add(db_image)
                    session.commit()
                    session.refresh(db_image)
                    
                    
                    self.images = [db_image] + self.images
                        
            except Exception as e:
                print(f"Database error: {e}")
                return rx.window_alert("Error creating database entry.")
        
        # Очищаем поле caption
        self.caption = ""
        # Перезагружаем список изображений
        self.on_load()

def image_card(image: rx.Var[Image]):
    return rx.vstack(
        rx.image(
            src=image.path,
            height="200px",
            width="auto",
        ),
        rx.text(image.caption),
        rx.moment(
            image.created_at,
            format="YYYY-MM-DD HH:mm:ss"
        ),
        padding="5",
        border="1px solid #eaeaea",
        border_radius="md",
        width="100%",
    )

def index():
    return rx.vstack(
        rx.vstack(
            rx.heading("Add new image"),
            rx.text_area(
                placeholder="Caption for image",
                value=State.caption,
                on_change=State.set_caption,
                margin_bottom="5",
            ),
            rx.upload(
                rx.vstack(
                    rx.button(
                        "Выберите файл",
                        color="rgb(107,99,246)",
                        bg="white",
                        border="1px solid rgb(107,99,246)",
                    ),
                    rx.text(
                        "upload image..."
                    ),
                ),
                id="upload1",
                border="1px dotted rgb(107,99,246)",
                padding="2em",
                accept={
                    "image/png": [".png"],
                    "image/jpeg": [".jpg", ".jpeg"],
                },
                margin_bottom="5",
            ),
            rx.hstack(
                rx.foreach(
                    rx.selected_files("upload1"),
                    rx.text
                )
            ),
            rx.hstack(
                rx.button(
                    "Upload",
                    on_click=State.handle_upload(
                        rx.upload_files(
                            upload_id="upload1",
                            on_upload_progress=State.handle_upload_progress,
                        )
                    ),
                ),
                rx.button(
                    "Clear",
                    on_click=rx.clear_selected_files("upload1"),
                ),
                spacing="5",
            ),
            rx.cond(
                State.processing,
                rx.vstack(
                    rx.text(f"Загрузка: {State.progress}%"),
                    rx.progress(value=State.progress, max=100),
                ),
            ),
            padding="2em",
            border="1px solid #eaeaea",
            border_radius="10px",
            width="100%",
            margin_bottom="2em",
        ),
        
        rx.heading("Gallery"),
        rx.vstack(
            rx.foreach(
                State.images,
                image_card,
            ),
            spacing="5", 
            width="100%",
        ),
        width="100%",
        max_width="800px",
        margin="0 auto",
        padding="2em",
        on_mount=State.on_load,
    )
    
    

app = rx.App()
app.add_page(index, route="/")```

To start project:
reflex db init 
reflex db makemigrations
reflex db migrate
reflex run
Copy link

linear bot commented Apr 1, 2025

ENG-5350 Image upload

@vjabhi000985
Copy link

vjabhi000985 commented Apr 11, 2025

Hi! I'd like to work on this issue. Could you please assign it to me?

@AnonimPython
Copy link
Author

Hi! I'd like to work on this issue. Could you please assign it to me?

Hi! Yes, take this.

@vjabhi000985
Copy link

@AnonimPython Thank you so much for this opportunity. Can you provide a reference to this code block? It would be helpful.

@AnonimPython
Copy link
Author

@AnonimPython Thank you so much for this opportunity. Can you provide a reference to this code block? It would be helpful.

Yes! Ok, I will create a repo for u and give a link.

@vjabhi000985
Copy link

@AnonimPython I will be waiting for your response.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants