CRUD with flask rookie mistake - python

This is the thing, I was trying to make a crud for a rest api for a movie app, I was able to successfully perform the functionalities with flask to create a movie within the json, to delete a movie, and to list them, but I have problems with being able to edit one of the movies inside the JSON since I don't know how to access a sector of it to be able to modify it, this is what I was trying:
def __init__(self, idpelicula, nombre, descripcion, elenco, restriccionedad, fecha, calificacion):
self.idpelicula = idpelicula
self.nombre = nombre
self.descripcion = descripcion
self.elenco = elenco
self.restriccionedad = restriccionedad
self.fecha = fecha
self.calificacion = calificacion
movies_list = [
Peliculas(1, "Shrek", "Pelicula de Ogro", "Shrek, Fiona", "+APTA", "2001", "10"),
Peliculas(2, "Shrek2", "Otra Pelicula de Ogro", "Shrek, Fiona", "+APTA", "2005", "10"),
]
#app.route("/movies")
def list_movies():
return jsonify([pelicula.__dict__ for pelicula in movies_list])
#app.route("/movies/<id_search_movie>")
def obtener_pelicula(id_search_movie):
for pelicula in movies_list:
if pelicula.idpelicula == int(id_search_movie):
return jsonify(pelicula.__dict__)
return "Pelicula no encontrada", 404
#app.route("/movies", methods=['POST'])
def create_movie():
movie_data = request.get_json()
new_movie = Peliculas(movie_data["idpelicula"], movie_data["nombre"], movie_data["descripcion"],
movie_data["elenco"], movie_data["restriccionedad"], movie_data["fecha"],
movie_data["calificacion"])
movies_list.append(new_movie)
return "OK", 200
#app.route("/movies/<id_delete_movie>", methods=['DELETE'])
def delete_movie(id_delete_movie):
for pelicula in movies_list:
if pelicula.idpelicula == int(id_delete_movie):
movies_list.remove(pelicula)
return "OK", 200
This is what I dont know how to do, (I know its wrong, and that this isn't even the logic to do this), but this is what I tried:
#app.route("/movies", methods=['PUT'])
def edit_movie():
movie_data = request.get_json()
new_movie = Peliculas(movie_data["idpelicula"], movie_data["nombre"], movie_data["descripcion"],
movie_data["elenco"], movie_data["restriccionedad"], movie_data["fecha"],
movie_data["calificacion"])
movies_list.append(new_movie)
return "OK", 200
Any help, even from the point of view of the logic behind doing this will come handy. Thanks to you all.

There is a ton of problems with the way you are coding this at the moment, but here i will show you how you can edit an object in the way you are currently doing it.
So with your approach the edit view should be like this:
#app.route("/movies", methods=['PUT'])
def edit_movie():
# Accessing data from request
movie_data = request.get_json()
# Accesing Object from the movie-list by ID
for movie in movies_list:
if movie.idpelicula == movie_data["idpelicula"]:
edited_movie = movie
# Modifying the object attributes
for name, value in movie_data.items():
if hasattr(edited_movie, name):
setattr(edited_movie, name, value)
return "OK", 200
The problem here is that you were creating a new instance instead of editing an existing one.
in the future you could explore the usage of SQLAlchemy models so you can persist the data in a database, and still be managing objects.
PD1: Finally i recommend you be coherent with the naming, by this i mean if you are calling your variables and classes in spanish Pelicula, peliculas, try to use the same naming throught all your code, same if you use english.
PD2: Study some basic python usage of classes and variable assignment, so you can improve your code.
Greetings from Chile.

Related

Why Python doesn´t save my model to database using object .save()?

I have a function in views.py accepting petitions that get some text and a book pk and save the text to a fragments table and update the book text with the new fragment.
The fragments are saved correctly, but the book doesn't. I get the response, but it doesn't save to the database when I manually check it.
This is my code:
profilelogged = validtoken(request.META['HTTP_MYAUTH'])
if not profilelogged:
return HttpResponse('Unauthorized', status=401)
else:
index = request.GET.get('id', 0)
petitiontext = request.GET.get('texto', '')
petitiontext = petitiontext.strip()
todaynoformat = datetime.now()
bookselected = Books.objects.filter(pk=index).first()
actualwait = Waits.objects.filter(book=bookselected).order_by('ordernum').first()
if not actualwait:
response = 'MAL: No hay nadie en espera'
else:
profilewaiting = actualwait.profile
if profilewaiting.pk == profilelogged.pk and actualwait.writting == 1:
newfragment = Fragments(profile=profilelogged, book=bookselected, date=todaynoformat.isoformat(), texto=petitiontext)
newfragment.save()
newtextfull = bookselected.text+" "+petitiontext
bookselected.text = newtextfull
bookselected.save()
actualwait.writting = 2
actualwait.save()
response = bookselected.text
else:
response = 'MAL: No eres el siguiente en la lista o no estas activado para escribir'
return HttpResponse(response)
Forget about the waiting thing, its some waitlist i used to check if the user is able to submit fragments or not and thats working good.
Any thoughts on why book is not saving to DB? I'm using this object.save() method in other functions and its working, but here it doesn't.
Thanks.
Ok, my bad.
I was trying to update same object on two different functions. So I had to figure out how to update it on one unique function and that's the solution.
Thanks anyway.

Short description isn't working for delete selected (delete_selected.short_description isn't changing the name)

I am currently trying to change the name of the "Delete Selected" admin action. I have already effectively override the default (so I can store some data before completely deleting it), but now I want to change the option from the vague "Deleted selected" to something more specific like "Deleted all selected registrations." Or, at least, for it to say, "Deleted selected registrations" like it did before I overwrote the function.
I have so far tried this:
delete_selected.short_description = 'Delete all selected registrations'
But the option is still "Deleted selected." Is there a way to fix this?
Here's my code:
def delete_selected(modeladmin, request, queryset):
"""
This overrides the defult deleted_selected because we want to gather the data from the registration and create a
DeletedRegistration object before we delete it.
"""
for registration in queryset:
reg = registration.get_registrant()
if registration.payment_delegation:
delegate_name = registration.payment_delegation.name
delegate_email = registration.payment_delegation.email
else:
delegate_name = None
delegate_email = None
registration_to_delete = DeletedRegistration.objects.create(
registrant_name = reg.full_name(),
registrant_email = reg.email,
registrant_phone_num = reg.phone,
delegate_name = delegate_name,
delegate_email = delegate_email,
# Filtering out people (with True) who couldn't participate in events because we are only interested in the people
# we had to reserve space and prepare materials for.
num_of_participants = registration.get_num_party_members(True),
special_event = registration.sibs_event,
)
registration.delete()
delete_selected.short_description = 'Delete all selected registrations'
edit: just tried delete_selected.list_display that didn't work either
You can't have it in the function, so I just had to tab it back one space and it worked.
example:
def delete_selected(modeladmin, request, queryset)
code
delete_selected.short_description = "preferred name"
thanks.

Python Praw ways to store data for calling later?

Is a dictionary the correct way to be doing this? Ideally this will be more then 5+ deep. Sorry my only language experience is powershell there I would just make an array of object. Im not looking for someone to write the code I just wanna know if there is a better way?
Thanks
Cody
My Powershell way:
[$title1,$title2,$title3]
$titleX.comment = "comment here"
$titleX.comment.author = "bob"
$titleX.comment.author.karma = "200"
$titleX.comment.reply = "Hey Bob love your comment."
$titleX.comment.reply.author = "Alex"
$titleX.comment.reply.reply = "I disagree"
#
Python code Borken:
import praw
d = {}
reddit = praw.Reddit(client_id='XXXX',
client_secret='XXXX',
user_agent='android:com.example.myredditapp:'
'v1.2.3 (by /u/XXX)')
for submission in reddit.subreddit('redditdev').hot(limit=2):
d[submission.id] = {}
d[submission.id]['comment'] = {}
d[submission.id]['title']= {}
d[submission.id]['comment']['author']={}
d[submission.id]['title'] = submission.title
mySubmission = reddit.submission(id=submission.id)
mySubmission.comments.replace_more(limit=0)
for comment in mySubmission.comments.list():
d[submission.id]['comment'] = comment.body
d[submission.id]['comment']['author'] = comment.author.name
print(submission.title)
print(comment.body)
print(comment.author.name)
print(d)
File "C:/git/tensorflow/Reddit/pull.py", line 23, in <module>
d[submission.id]['comment']['author'] = comment.author.name
TypeError: 'str' object does not support item assignment
#
{'6xg24v': {'comment': 'Locking this version. Please comment on the [original post](https://www.reddit.com/r/changelog/comments/6xfyfg/an_update_on_the_state_of_the_redditreddit_and/)!', 'title': 'An update on the state of the reddit/reddit and reddit/reddit-mobile repositories'}}
I think your approach using a dictionary is okay, but you might also solve this by using a data structure for your posts: Instead of writing
d[submission.id] = {}
d[submission.id]['comment'] = {}
d[submission.id]['title']= {}
d[submission.id]['comment']['author']={}
d[submission.id]['title'] = submission.title
you could create a class Submission like this:
class Submission(object):
def __init__(self, id, author, title, content):
self.id = id
self.author = author
self.title = title
self.content = content
self.subSubmissions = {}
def addSubSubmission(self,submission):
self.subSubmission[submission,id] = submission
def getSubSubmission(self,id):
return self.subSubmission[id]
by using you could change your code to this
submissions = {}
for sm in reddit.subreddit('redditdev').hot(limit=2):
submissions[sm.id] = Submission(sm.id, sm.author, sm.title, sm.content)
# I am not quite sure what these lines are supposed to do, so you might be able to improve these, too
mySubmission = reddit.submission(id=sm.id)
mySubmission.comments.replace_more(limit=0)
for cmt in mySubmission.comments.list():
submissions[sm.id].addSubSubmission(Submission(cmt.id, cmt.title, cmt.author, cmt.body))
By using this apporach you are also able to export the code to readout the comments/subSubmissions into an extra function which can call itself recursively, so that you can read infitive depths of the comments.

Django-tables2 - column name is changed after refreshing page

I'm facing a very weird behaviour of Django and Django-tables2.
I use table to help to render multiple types of documents.
For simplicity, there are two types of documents - 'faktura' and 'dobropis'.
'dobropis' has to have first column labeled "Dobropisujeme Vám" and 'faktura' - "Názov položky" + those columns are equal.
So I'm checking, if the type of Document is 'faktura' or 'dobropis' inside Table __init__ function and accordingly set
self.base_columns['column'].verbose_name = ...
The weird thing is that it works, but only after second refresh.
Situation: I've opened 'faktura' page - I can see 'Názov položky' which is ok. Then I open 'dobropis' page and I see 'Názov položky' label again. Then, if I refresh again, there is 'Dobropisujeme Vám'. Then, after each refresh, I see correct label - 'Dobropisujeme Vám'. But, if I open 'faktura' page, there is 'Dobropisujeme Vám' too for the first time, after second refresh it goes normal.
class PolozkyTable(tables.Table):
nazov_polozky = tables.columns.Column(orderable=False)
pocet = tables.columns.Column(orderable=False)
jednotka = tables.columns.Column(orderable=False)
cena = tables.columns.Column(orderable=False, verbose_name=u'Jednotková cena')
zlava = tables.columns.Column(orderable=False)
dph = tables.columns.Column(orderable=False)
celkom = tables.columns.Column(orderable=False)
class Meta:
model = Polozka
fields = ['nazov_polozky', 'pocet', 'jednotka', 'cena', 'zlava', 'dph', 'celkom']
attrs = {'class': 'table table-striped table-hover'}
def __init__(self, *args, **kwargs):
typ = kwargs.pop('typ')
super(PolozkyTable, self).__init__(*args, **kwargs)
if typ == 'dobropis':
self.base_columns['nazov_polozky'].verbose_name = u'Dobropisujeme Vám'
self.exclude = ['zlava', 'dph']
else:
self.base_columns['nazov_polozky'].verbose_name = u'Názov položky'
def render_cena(self, record):
return '{} {}'.format(record.cena, record.doklad.get_fakturacna_mena_display().encode('utf-8'))
def render_celkom(self, record):
return '{} {}'.format(record.celkom, record.doklad.get_fakturacna_mena_display().encode('utf-8'))
#login_required
def doklad_detail(request):
doklad = get_object_or_404(Doklad, pk=request.GET.get('id'))
polozky_table = PolozkyTable(doklad.polozky.all(),typ=doklad.typ)
return render(request, 'pdf/{}_pdf_template.html'.format(doklad.typ),
{'doklad': doklad, 'polozky_table': polozky_table})
There is no cache in this project and I really don't know what it could be.
Do you know?
EDIT:
Moreover, when I open 'faktura' after restarting the server, it shows camelcased 'Názov Položky' instead of 'Názov položky'. This is another weird thing because I searched whole project for case sensitive 'Názov Položky' and there is no such string.
EDIT2:
I've solved this creating separate table for 'dobropis' but I'm still curious which caused this problem. My colleague had the same problem on his PC.
You shouldn't be modifying base_columns in the __init__ method -- you are changing the value on the class, so it affects other views as well.
The base_columns have already been copied in the super() call before you alter them, so the changes only show up the next time you access the view.
It looks like you should be modifying self.columns instead. That should only affect the instance. Try setting header instead of verbose_name.
self.columns['nazov_polozky'].header = u'Dobropisujeme Vám'

Using memcache to store obj's in google app engine

I'm trying to use memcache to cache data retrevied from the datastore. Storing stings works fine. But can't one store an object? I get an error "TypeError: 'str' object is not callable" when trying to store with this:
pageData = StandardPage(page)
memcache.add(memcacheid, pageData, 60)
I've read in the documentation that it requires "The value type can be any value supported by the Python pickle module for serializing values." But don't really understand what that is. Or how to convert pageData to it.
Any ideas?
..fredrik
EDIT:
I was a bit unclear. PageType is an class that amongst other thing get data from the datastore and manipulate it. The class looks like this:
class PageType():
def __init__(self, page):
self.pageData = PageData(data.Modules.gql('WHERE page = :page', page = page.key()).fetch(100))
self.modules = []
def renderEditPage(self):
self.addModules()
return self.modules
class StandardPage(PageTypes.PageType):
templateName = 'Altan StandardPage'
templateFile = 'templates/page.html'
def __init__(self, page):
self.pageData = PageTypes.PageData(data.Modules.gql('WHERE page = :page', page = page.key()).fetch(100))
self.modules = []
self.childModules = []
for child in page.childPages:
self.childModules.append(PageTypes.PageData(data.Modules.gql('WHERE page = :page', page = child.key()).fetch(100)))
def addModules(self):
self.modules.append(PageTypes.getStandardHeading(self, 'MainHeading'))
self.modules.append(PageTypes.getStandardTextBox(self, 'FirstTextBox'))
self.modules.append(PageTypes.getStandardTextBox(self, 'SecondTextBox'))
self.modules.append(PageTypes.getStandardHeading(self, 'ListHeading'))
self.modules.append(PageTypes.getStandardTextBox(self, 'ListTextBox'))
self.modules.append(PageTypes.getDynamicModules(self))
You can use db.model_to_protobuf to turn your object into something that can be stored in memcache. Similarly, db.model_from_protobuf will get your object back.
Resource:
Datastore Functions

Categories