Flask SqlAlchemy AttributeError: у объекта 'str' нет атрибута '_sa_instance_state' - PullRequest
0 голосов
/ 27 марта 2020

Итак, я пытаюсь добавить имя изображения, которое я сохраняю в указанном каталоге, но эта ошибка продолжает появляться, и в базу данных ничего не добавляется, хотя изображения продолжают сохраняться в указанном каталоге. Вот все мои файлы Models.py

from shop import db
from datetime import datetime


class Product(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)
    price = db.Column(db.Numeric(10,2), nullable=False)
    stock = db.Column(db.Integer, nullable=False)
    desc = db.Column(db.Text, nullable=False)
    pub_date = db.Column(db.DateTime, nullable=False,
        default=datetime.utcnow)

    brand_id = db.Column(db.Integer, db.ForeignKey('brand.id'),
        nullable=False)
    brand = db.relationship('Brand',
        backref=db.backref('brands', lazy=True))

    category_id = db.Column(db.Integer, db.ForeignKey('category.id'),
        nullable=False)
    category = db.relationship('Category',
        backref=db.backref('categories', lazy=True))

    image_1 = db.Column(db.String(256), nullable=False, default='image1.jpg')
    image_2 = db.Column(db.String(256), nullable=False, default='image2.jpg')
    image_3 = db.Column(db.String(256), nullable=False, default='image3.jpg')

    def __repr__(self):
        return '<Product %r>' % self.name

class Brand(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), nullable=False, unique=True)

class Category(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), nullable=False, unique=True)

db.create_all()

forms.py

from flask_wtf.file import FileAllowed, FileField, FileRequired
from wtforms import Form,StringField, IntegerField, BooleanField, TextAreaField, validators

class AddProducts(Form):
    name = StringField("Name", [validators.DataRequired()])
    price = IntegerField("Price:RS ", [validators.DataRequired()])
    stock = IntegerField("Stock", [validators.DataRequired()])
    desc = TextAreaField("Description", [validators.DataRequired()])
    # colors = TextAreaField("Colors", [validators.DataRequired()])

    image_1 = FileField('Image 1', [FileRequired(), FileAllowed(['jpg, jpeg, png, svg, gif']), "Images Only please"])
    image_2 = FileField('Image 2', [FileRequired(), FileAllowed(['jpg, jpeg, png, svg, gif']), "Images Only please"])
    image_3 = FileField('Image 3', [FileRequired(), FileAllowed(['jpg, jpeg, png, svg, gif']), "Images Only please"]) 

* rout.py


@app.route('/addproduct', methods=["GET", "POST"])
def addproduct():
    brands = Brand.query.all()
    categories = Category.query.all()
    form = AddProducts(request.form)
    if request.method == "POST":
        name = form.name.data
        price = form.price.data
        stock = form.stock.data
        desc = form.desc.data
        brand = request.form.get('brand')
        category = request.form.get('category')
        image_1 = photos.save(request.files['image_1'] , name=secrets.token_hex(10) + '.')
        image_2 = photos.save(request.files['image_2'] , name=secrets.token_hex(10) + '.')
        image_3 = photos.save(request.files['image_3'] , name=secrets.token_hex(10) + '.')
        print(f"Image 1 name:{image_1}, its type:{type(image_1)}")
        product = Product(name=name, price=price, stock=stock, desc=desc, brand=brand, category=category, 
                                image_1=image_1,image_2=image_2, image_3=image_3)
        db.session.add(product)
        flash(f"{name} has been added to database.", 'success')
        db.session.commit()
        return redirect(url_for('admin'))
    return render_template('products/addproduct.html', title='Add Product', form=form, brands=brands, 
                            categories=categories)

Все типы изображений являются строками, а поля модели также являются строковыми, но я все еще получаю эту ошибку. Вот моя html страница для этой формы

{% extends 'layout.html' %}

{% block body_block %}
{% include '_messages.html' %}
<div class="container">
    <div class="row">
    <div class="col-md-2"></div>
    <div class="col-md-8">
        <h2 class="text-center bg-info p-2">
            Add product
        </h2>
        {% from '_formhelpers.html' import render_field %}
        <form action="" method="POST" enctype="multipart/form-data">
            {{ render_field(form.name, class="form-control", placeholder="Product Name")}}
            {{ render_field(form.price, class="form-control", placeholder="Price") }}
            {{ render_field(form.stock, class="form-control", placeholder="Stock") }}
            <label for="brand">Add a Brand</label>
            <select class="form-control" name="brand" id="brand">
                <option value="" class="form-control" required> Select a Brand</option>
                {% for brand in brands%}
                    <option value="brand.id" class="form-control">{{brand.name}}</option>
                {% endfor %}
            </select>
            <label for="category">Add a Category</label>
            <select class="form-control" name="category" id="category">
                <option value="" class="form-control" required> Select a Category</option>
                {% for category in categories %}
                    <option value="category.id" class="form-control">{{category.name}}</option>
                {% endfor %}
            </select>
            {{ render_field(form.desc, class="form-control", placeholder="Product Description", rows=10) }}
            <div class="container">
                <div class="row">
                    <div class="col-md-4">
                        {{ render_field(form.image_1, class="form-control")}}
                    </div>
                    <div class="col-md-4">
                        {{ render_field(form.image_2, class="form-control")}}
                    </div>
                    <div class="col-md-4">
                        {{ render_field(form.image_3, class="form-control")}}
                    </div>
                </div>
            </div>

            <button type="submit" class="btn btn-outline-info mt-4">Add Product</button>
        </form>
    </div>
    <div class="col-md-2"></div>
</div>
</div>
{% endblock body_block %}

1 Ответ

0 голосов
/ 27 марта 2020

Я упростил ваш пример ниже. Ошибка возникает в 5-й строке:

image_1 = photos.save()
image_2 = photos.save()
image_3 = photos.save()
print(f"Image 1 name:{image_1}, its type:{type(image_1)}")
product = Product(brand=brand, category=category)           # <- HERE
db.session.add(product)

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

Так как вы указали в models.py, что атрибуты brand и category являются атрибутами отношений (db.relationship()) Эти атрибуты ожидают объект ORM, и вы передаете им строку.

Создайте экземпляры объектов ORM перед передачей их в Product, например, так:

brand = Brand(name="brandname")
category = Category(name="categoryname")

product = Product(brand=brand, category=category)

Это что указано в этом ответе, понятно, что это длинное чтение: { ссылка }

...