Flask SqlAlchemy AttributeError: 'str' object has no attribute '_sa_instance_state'
Flask SqlAlchemy AttributeError: 'str' object has no attribute '_sa_instance_state'
因此,我尝试添加我保存在指定目录中的图像名称,但此错误不断出现并且数据库中没有添加任何内容,尽管图像一直保存在指定目录中。
这是我所有的文件
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"])
*routes.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 %}
我在下面简化了您的示例。错误发生在第 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)
这就是这个答案中的内容,可以理解这是一篇很长的文章:
因此,我尝试添加我保存在指定目录中的图像名称,但此错误不断出现并且数据库中没有添加任何内容,尽管图像一直保存在指定目录中。 这是我所有的文件 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"])
*routes.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 %}
我在下面简化了您的示例。错误发生在第 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)
这就是这个答案中的内容,可以理解这是一篇很长的文章: