[SQLAlchemy] Relacje w bazie danych

Odpowiedz Nowy wątek
2020-02-26 20:31

Rejestracja: 1 rok temu

Ostatnio: 1 godzina temu

0

Witam, mam następujące modele w mojej aplikacji(Flask):

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key = True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    password = db.Column(db.String(30), nullable=False)
    email = db.Column(db.String(100), nullable=False, unique=True)
    adverts = db.relationship('Advert', backref='autor', lazy=True)
    messages_sent = db.relationship('Message',foreign_keys='Message.sender_id', backref='author', lazy='dynamic')
    messages_received = db.relationship('Message',foreign_keys='Message.recipient_id', backref='recipient', lazy='dynamic')
    telephone = db.Column(db.String(15))

    def __repr__(self):
        return f"User('{self.username}', '{self.email}'"

class Advert(db.Model):

    id = db.Column(db.Integer, primary_key=True)
    date = db.Column(db.DateTime, nullable=False, default = datetime.utcnow)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable = False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    category = db.Column(db.String(50), nullable=False)
    price = db.Column(db.Integer)
    city = db.Column(db.String(), nullable=False)

    def __repr__(self):
        return f"Advert('{self.title}', '{self.date}', '{self.category}')"

class Message(db.Model):

    id = db.Column(db.Integer, primary_key=True)
    sender_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    recipient_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    title = db.Column(db.String(100), nullable=False)
    body = db.Column(db.String(300), nullable=False)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)
    ad_title = db.relationship('Advert', foreign_keys='Advert.title', backref='adtitle', lazy='dynamic')

    def __repr__(self):
        return f"Message('{self.body}')"

Chcę zrobić tak, aby każda wiadomość miała w sobie informacje na jakie ogłoszenie została wysłana. W tym celu zrobiłem relacje dodając do klasy Message

ad_title = db.relationship('Advert', foreign_keys='Advert.title', backref='adtitle', lazy='dynamic')

Która wskazuję na tytuł z klasy Advert ale ten sposób niestety nie działa. Czy ktoś może wie gdzie znajduję się błąd?

Pozostało 580 znaków

2020-02-26 22:49

Rejestracja: 5 lat temu

Ostatnio: 1 godzina temu

Lokalizacja: Chorzów

1

Błąd czego ? Co nie działa ?


Projektowanie i programowanie. Hobbystycznie elektronika i audio oszołom.

Pozostało 580 znaków

2020-02-26 23:27

Rejestracja: 1 rok temu

Ostatnio: 1 godzina temu

0

Wyskakuje błąd przy odpalaniu serwera

sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship Message.ad_title - there are no foreign keys linking these tables.  Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
edytowany 1x, ostatnio: Rzemysł, 2020-02-26 23:28

Pozostało 580 znaków

2020-02-28 22:15

Rejestracja: 2 lata temu

Ostatnio: 3 tygodnie temu

1

Kolumna ad_title nie spełnia wymaganych kryteriów, aby mogła pełnić rolę klucza obcego.

https://en.wikipedia.org/wiki/Foreign_key#Summary

Poza tym tytuł to słaby pomysł na klucz obcy. Pomyśl, że wielu użytkowników może mieć podobny tytuł - co wtedy? Pomyśl, że użytkownik może potrzebować korekty w tytule, co wtedy?

Nie prościej byłoby użyć odwołania do primary key z modelu Advert? Gdy będziesz potrzebował odczytanie tytułu ogłoszenia wtedy wystarczy, by ORM zrobił za Ciebie złączenie.

Przy okazji przemyśl sobie pola messages_sent i messages_received, bo prawdopodobnie wyświetlając wynik (który będzie dyskusją), będziesz potrzebował wykonać conajmniej 2 zapytania i sortować wspólny wyniki po stronie pythona. Normalnie posortowane wiadomości dyskusji mógłbyś uzyskać robiąc odpowiednie zapytanie na samym modelu Message.

edytowany 1x, ostatnio: devpython, 2020-02-28 22:16

Pozostało 580 znaków

Odpowiedz

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0