filament_profile_default.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. from datetime import datetime
  2. from sqlalchemy import DateTime, Float, ForeignKey, Integer, String, UniqueConstraint, func
  3. from sqlalchemy.orm import Mapped, mapped_column, relationship
  4. from backend.app.core.database import Base
  5. class FilamentProfileDefault(Base):
  6. """The profiles a new spool of one product starts with (#1326).
  7. A spool's slicer preset, per-model preset overrides and K profiles describe
  8. the filament, not the roll, so the replacement for an empty spool wants the
  9. same ones. A default holds them once per product, keyed on the
  10. (brand, material, subtype, color_name) strings the spool carries, and every
  11. create path copies them onto the new spool -- a copy, not a link: editing a
  12. default later leaves existing spools alone.
  13. ``color_name`` "" is the default for every colour of the product; a row
  14. with a colour wins over it, per preset and per hotend (see
  15. ``services.filament_profile_default.resolve_profile_default``), so the
  16. first spool of a new colour still gets the product's K profiles and a
  17. colour calibrated on its own keeps its values. Empty strings rather than
  18. NULL for the same reason as ``spool_filament_preset.nozzle_diameter``:
  19. NULLs compare distinct in a UNIQUE constraint on both databases.
  20. Shared by both inventory modes: the key is the product, which a Spoolman
  21. spool carries as well as an internal one.
  22. """
  23. __tablename__ = "filament_profile_default"
  24. id: Mapped[int] = mapped_column(primary_key=True)
  25. # The four fields folded in Python (services.filament_profile_default.match_key),
  26. # not in SQL: SQLite's lower() folds ASCII only, so "Красный" would never
  27. # match its own row there -- the same reason Supplier.name_key exists.
  28. match_key: Mapped[str] = mapped_column(String(320), unique=True)
  29. brand: Mapped[str] = mapped_column(String(100), default="")
  30. material: Mapped[str] = mapped_column(String(50))
  31. subtype: Mapped[str] = mapped_column(String(50), default="")
  32. color_name: Mapped[str] = mapped_column(String(100), default="")
  33. # Lengths of the Spoolman write schema, the wider of the two inventories.
  34. slicer_filament: Mapped[str | None] = mapped_column(String(128))
  35. slicer_filament_name: Mapped[str | None] = mapped_column(String(255))
  36. created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
  37. updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
  38. presets: Mapped[list["FilamentProfileDefaultPreset"]] = relationship(
  39. back_populates="profile_default", cascade="all, delete-orphan"
  40. )
  41. k_profiles: Mapped[list["FilamentProfileDefaultKProfile"]] = relationship(
  42. back_populates="profile_default", cascade="all, delete-orphan"
  43. )
  44. class FilamentProfileDefaultPreset(Base):
  45. """A default's preset for one printer model and nozzle; the same row as
  46. ``SpoolFilamentPreset``."""
  47. __tablename__ = "filament_profile_default_preset"
  48. __table_args__ = (UniqueConstraint("profile_default_id", "printer_model", "nozzle_diameter"),)
  49. id: Mapped[int] = mapped_column(primary_key=True)
  50. profile_default_id: Mapped[int] = mapped_column(
  51. ForeignKey("filament_profile_default.id", ondelete="CASCADE"), index=True
  52. )
  53. printer_model: Mapped[str] = mapped_column(String(50))
  54. nozzle_diameter: Mapped[str] = mapped_column(String(10), default="")
  55. slicer_filament: Mapped[str | None] = mapped_column(String(128))
  56. slicer_filament_name: Mapped[str | None] = mapped_column(String(255))
  57. profile_default: Mapped[FilamentProfileDefault] = relationship(back_populates="presets")
  58. class FilamentProfileDefaultKProfile(Base):
  59. """A default's K profile for one hotend; the same row as ``SpoolKProfile``.
  60. Unique per hotend like ``spoolman_k_profile``, so a default copies onto a
  61. Spoolman spool without tripping that table's constraint. Goes with its
  62. printer, as a spool's K profiles do.
  63. """
  64. __tablename__ = "filament_profile_default_k_profile"
  65. __table_args__ = (UniqueConstraint("profile_default_id", "printer_id", "extruder", "nozzle_diameter"),)
  66. id: Mapped[int] = mapped_column(primary_key=True)
  67. profile_default_id: Mapped[int] = mapped_column(
  68. ForeignKey("filament_profile_default.id", ondelete="CASCADE"), index=True
  69. )
  70. printer_id: Mapped[int] = mapped_column(ForeignKey("printers.id", ondelete="CASCADE"), index=True)
  71. extruder: Mapped[int] = mapped_column(Integer, default=0)
  72. nozzle_diameter: Mapped[str] = mapped_column(String(10), default="0.4")
  73. nozzle_type: Mapped[str | None] = mapped_column(String(50))
  74. k_value: Mapped[float] = mapped_column(Float)
  75. name: Mapped[str | None] = mapped_column(String(100))
  76. cali_idx: Mapped[int | None] = mapped_column(Integer)
  77. setting_id: Mapped[str | None] = mapped_column(String(50))
  78. profile_default: Mapped[FilamentProfileDefault] = relationship(back_populates="k_profiles")