How can I update a row in DB using transaction.manager in Pyramid? Here is what I have:
DBSession:
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
View:
def create_update(request, post):
title = request.POST.get('title', None)
content = request.POST.get('content', None)
post.title = title
post.content = content
with transaction.manager:
if post.id is None:
DBSession.add(post)
transaction.commit()
This is how I get an existing post from DB:
def by_slug(slug):
return DBSession.query(BlogPost).filter(BlogPost.slug == slug).first()
where BlogPost is a sqlalchemy model.
When I create a new post, everything is fine, it is added and saved in DB, however, nothing happens when I edit an existing post. I've tried DBSession.flush(), result is the same - I can create a new post, but existing one is not updated. What am I missing?
Why your use transaction here?
The ZopeTransactionExtension on the DBSession in conjunction with the pyramid_tm being active on your project will handle all commits for you.
so just try this:
def create_update(request, post):
title = request.POST.get('title', None)
content = request.POST.get('content', None)
post.title = title
post.content = content
if post.id is None:
DBSession.add(post)
Apparently, the issue was, that I didn't have pyramid_tm under pyramid.includes in ini configuration:
[app:main]
use = egg:myproject
pyramid.includes =
pyramid_jinja2
pyramid_tm #this was missing
Weird, that I was not seeing any errors or anything, and it sort of worked, but was giving a lot of headaches.
Related
Getting an error always
The current path, <code>api/det/1</code>, didn’t match any of these.
My urls.py
url(r'^api/det/<int:id>',views.DetailsAPI.as_view(),name='DetailsAPI')
My views.py
class DetailsAPI(APIView):
def get(self,id):
filter_list=Details.objects.all()
#filter_list = Details.objects.get(id=id)
envid = self.kwargs['id']
df = read_frame(filter_list)
df_det = df.loc[df['Id'] == int(id)]
df_final=df_det.to_json(orient='records')
return HttpResponse(df_final, content_type = 'application/json')
I'm sure there is some simple stuff that i'm missing and i can't get it to work with whatever syntax i try.. Any suggestions?
Changing the url to the below one worked.
url(r'^api/det/(?P<id>\d+)',views.DetailsAPI.as_view(),name='DetailsAPI')
I'm new to flask and in order to refactor an existing route method on a Flask API, i'm looking for the best practice to reduce it and call method inside the route method.
Acutally the route is designed like that :
#qman.route('/add_report/', methods=['POST'])
def create_report():
"""
Check if data send throught http POST request, is correct based on the report
schema and not already recorded in the table report of the DB.
:param: data from POST request
:return: Ok, valide and imported -> 201, Correct but AlreadyKnown -> 208,
InvalideScheme -> 422
"""
jsonData = request.get_json()
reportSchema = ReportSchema()
try:
data = reportSchema.load(jsonData)
except ValidationError as validation_err:
return(validation_err.messages), 422
nameReportCheck = data["report_name"]
report = Report.query.filter_by(report_name=nameReportCheck).first()
if report is None:
# Create new report
report = Report(
report_name=nameReportCheck,
hostname=data["hostname"],
status=data["status"],
date=data["date"],
nb_analysis_erreur=data["nb_analysis_erreur"]
)
db.session.add(report)
db.session.commit()
NewResult = reportSchema.dump(Report.query.get(report.reportID))
return{"message" : "Created new report" , "report" : NewResult}, 201
else :
reportAlreadyKnown = reportSchema.dump(Report.query.get(report.reportID))
return{"message" : "This report is already in the DB", "report" : reportAlreadyKnown}, 208
In the facts i would like to call a function named valid_schema(_schema, _jsondata) to check if the data send throught POST request match with my schema of model Report().
This function return a Response() object with serialized data and a 200 code if it's serialization is possible or an error that i cath inside try/except with 400 error code.
def valid_schema(_schema, _jsondata):
schema = _schema()
try:
data = schema.load(_jsondata)
except ValidationError as validation_err:
response = Response(validation_err.messages, 422)
return response
response = Response(data, 200, mimetype="application/json")
return response
Then the route method call an other function named create_report(report_data) if valid_schema(_schema, _jsondata) return report_data and 200 code in response object.
With his args, this method check if the records is not already in the DB and if is not, he create a Report() object from report_data arg and insert this one as a new record into the DB.
In fact I guess I can easily call this method inside the route function but it seem weird and there is probably an other way that I can't find, maybe decorator ?
One possibility for refactoring is the use of webargs, Flask-Marshmallow and marshmallow-sqlalchemy.
With Flask-Marshmallow you can check the input by specifying fields and validators. Webargs offers you the option of validating the defined scheme in a decorator and passing it on to the route as an argument. Using marshmallow-sqlalchemy in combination, this is immediately converted into a database model.
The following example is based on your information and gives you a brief overview of the usage. By defining your own error handler, the error messages can also be sent as JSON. Use in blueprints, views or the like is possible.
from flask import Flask
from flask import jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from marshmallow.validate import Length, OneOf
from webargs.flaskparser import use_args
app = Flask(__name__)
db = SQLAlchemy(app)
ma = Marshmallow(app)
class Report(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, unique=True)
hostname = db.Column(db.String)
status = db.Column(db.String)
date = db.Column(db.DateTime)
nb_analysis_error = db.Column(db.String)
class ReportSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Report
load_instance = True
sqla_session = db.session
name = ma.Str(required=True, validate=Length(min=3))
hostname = ma.Str(required=True)
date = ma.DateTime(required=True)
status = ma.Str(required=True, validate=OneOf(['online', 'offline']))
nb_analysis_error = ma.Str(missing='Unknown Error')
#app.route('/add_report', methods=['POST'])
#use_args(ReportSchema(), location='json')
def add_report(report):
report_schema = ReportSchema()
_report = Report.query.filter_by(name=report.name).first()
if _report:
report_data = report_schema.dump(_report)
return jsonify(message='Already Reported', report=report_data), 208
else:
db.session.add(report)
db.session.commit()
report_data = report_schema.dump(report)
return jsonify(message='Created', report=report_data), 201
with app.app_context():
db.drop_all()
db.create_all()
I have created a below function to update the device info in my django app, it does update the device information but also keeping the old data in the table, it should overwrite rather than duplicating the previous entry with the updated change.
can someone please take a look and suggest ?
def updateDevice(request, id):
hostlist_upt = HostList.objects.get(id__exact=id)
form = HostListForm(instance=hostlist_upt)
if request.method == 'POST':
form = HostListForm(request.POST, instance=hostlist_upt)
if form.is_valid():
form.save()
return redirect('/devices')
context = {'form': form}
return render(request, "add_device.html", context)
The new data has to be saved to the instance it belongs to.
In this case you need to change
def updateDevice(request, id):
hostlist_upt = HostList.objects.get(id=id)
if request.method == 'POST':
form = HostListForm(request.POST, instance=hostlist_upt)
if form.is_valid():
form.save()
return redirect('/devices')
else:
form = HostListForm(instance=hostlist_upt)
context = {'form': form}
return render(request, "add_device.html", context)
It seems like in my add_device.html page, I removed the following href and duplication stopped, I tried my original code what I pasted in the beginning and it looks fine now. It may be because it was routing to that add_device view instead of updateDevice view.
<form method="POST" action="/add_device">
{% csrf_token
change it to
<form method="POST" action="">
{% csrf_token
Thank you ViLuWi
I started testing views, but I found an error in the test, tell me where I went wrong, I'm just starting to learn, so don't judge strictly
my views:
`class MovieDetailView(Genre, DetailView):
model = Movie
slug_field = "url"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["star_form"] = RatingForm()
return context
`
my test looks like this:
`def test_starform_set_in_context(self):
request = RequestFactory().get('some-slug')
view = MovieDetailView()
view.setup(request)
context = view.get_context_data()
self.assertIn('star_form', context))`
url:
`path("<slug:slug>/", views.MovieDetailView.as_view(), name="movie_detail"),`
I think this is because Django's get_context_data() function uses the 'object' to pass it into the context.So, I suggest you to use get_object() method.
See this for more details: https://ccbv.co.uk/projects/Django/3.0/django.views.generic.detail/DetailView/
basically you need to return an object e.g.
def get_object(self,queryset=None):
obj = Movie.object.get(slug=self.kwargs.get('slug'))
return obj #also handle 404
or try one more thing :
slug_fields = slug
path should be
path("<str:slug>/", views.MovieDetailView.as_view(), name="movie_detail"),
I try to remove all head:book elements from following request excerpt:
<head:bookstore>
<head:book>9</head:book>
<head:book>10</head:book>
</head:bookstore>
requestHolder.getDomNodes("//head:bookstore/head:book").each {
requestNode.removeChild(it)
}
What am I doing wrong here?
updatE:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def requestHolder = groovyUtils.getXmlHolder("openBook#Request")
Here below the solution to remove the nodes of the XML, please notice that you can get the entire xml and you may need to edit the nodes name of the below script
// Get the entire request
def request = context.expand( '${Test Request#Request#declare namespace soap=\'http://www.w3.org/2003/05/soap-envelope\'; //soap:Envelope[1]}' )
// or create the XML
def BOOKS = '''
<bookstore>
<book>9</book>
<book>10</book>
</bookstore>
'''
def booksParser = new XmlParser().parseText(BOOKS)
def allBooks = booksParser.children()
booksParser.remove(allBooks)
new XmlNodePrinter().print(booksParser)
log.info booksParser