Django, Tastypie and retrieving the new object data - django

Im playing a little bit with heavy-client app.
Imagine I have this model:
class Category(models.Model):
name = models.CharField(max_length=30)
color = models.CharField(max_length=9)
Im using knockoutjs (but I guess this is not important). I have a list (observableArray) with categories and I want to create a new category.
I create a new object and I push it to the list. So far so good.
What about saving it on my db? Because I'm using tastypie I can make a POST to '/api/v1/category/' and voilĂ , the new category is on the DB.
Ok, but... I haven't refresh the page, so... if I want to update the new category, how I do it?
I mean, when I retrieve the categories, I can save the ID so I can make a put to '/api/v1/category/id' and save the changes, but... when I create a new category, the DB assign a id to it, but my javascript doesn't know that id yet.
in other words, the workflow is something like:
make a get > push the existing objects (with their ids) on a list > create a new category > push it on the list > save the existing category (the category doesnt have the id on the javacript) > edit the category > How I save the changes?
So, my question is, what's the common path? I thought about sending the category and retrieving the id somehow and assign it to my object on js to be able to modify it later. The problem is that making a POST to the server doesn't return anything.
In the past I did something like that, send the object via post, save it, retrieve it and send it back, on the success method retrieve the id and assign it to the js object.
Thanks!

Tastypie comes with an always_return_data option for Resources.
When always_return_data=True for your Resource, the API always returns the full object event on POST/PUT, so that when you create a new object you can get the created ID on the same request.
You can then just read the response from your AJAX and decode the JSON (i dont know about knockout yet).
see the doc : http://readthedocs.org/docs/django-tastypie/en/latest/resources.html?highlight=always_return_data#always-return-data
Hope this helps

Related

How to make filtering non model data in flask-admin

I have to make dashboard like view in flask-admin that will use data retrieved from external API. I have already written a functions that get date ranges and return data from that range. I should use BaseView probably but I don't know how to actually write it to make filters work. This is example function that i have to use: charts = generate_data_for_dashboard('164', '6423FACA-FC71-489D-BF32-3A671AB747E3', '2018-03-01', '2018-09-01'). Those params should be chosen from 3 different dropdowns. So far I know only how to render views with pre coded data like this :
class DashboardView(BaseView):
kwargs = {}
#expose('/', methods=('GET',))
def statistics_charts(self):
user = current_user
company = g.company
offices = Office.query.filter_by(company_id=company.id)
self.kwargs['user'] = user
self.kwargs['company'] = company
charts = generate_data_for_dashboard('164', '6423FACA-FC71-489D-BF32-3A671AB747E3', '2018-03-01', '2018-09-01')
self.kwargs['chart1'] = charts[0]
self.kwargs['chart2'] = charts[1]
return self.render('stats/dashboard.html', **self.kwargs)
But I need some kind of form to filter it. In addition date filter dropdown should have dynamic options : current_week, last_week, current_month, last_month, last_year. Don't know where to start.
You should use WTForms to build a form. You then have to decide if you want the data to be fetched on Submit or without a reload of the page. In the former case, you can just return the fetched information on the response page in your statistics_charts view. But if you want the data to update without a reload, you'll need to use JavaScript to track the form field changes, send the AJAX request to the API, and then interpret the resulting JSON and update your dashboard graphs and tables as needed.
I have not used it, but this tutorial says you can use Dash for substantial parts of this task, while mostly writing in Python. So that could be something to check out. There is also flask_jsondash which might work for you.

Django creating model instances - Validation before creation? In manager class? What is manager class for?

Say I have a class "Book" and I want to hit an API to verify the book exists before creating my model.
Do I create my "BookManager" class, override create, hit the api, and throw an exception if not valid or create if valid?
Then in Book I'd write objects = BookManager()
And create a book with.
new_book = Book.objects.create(name)?
Basically, this feels like a good way to organize my code, but I'm not sure if this is intended use for the Manager class as opposed to only modifying the queryset.
Additionally, does anyone have a good reference on how to structure your django rest framework app? Folder structure etc
I will start with very basics. I am assuming you api calls are simple get requests for now which you can achieve with python http package.
(I am assuming the api is a third party api for now)
you can define a simple view let say view name be : bookM
Next you have defined you model with lets say a primary key, book_name, other_attrs, date
now when you hit you api within this view you can get the response from get request
requests.get(url = URL, params = PARAMS)
With this if you find the response sent back with some text or null you can act on model as below :
book= BookSave(
name = "book1",
)
book.save()
If this is not the case you can save error message in python variable and display while rendering html
You can use this view as api and do ajax call from web page, as well in this case you can just return back messages

Updating and creating a new instance at the same time

When a user updates an invoice form, i want to create a new invoice record with the updated attributes, but also change one or two fields of the old record and save it, too.
How would the outline of a controller action look like which could accomplish this?
Instead of a controller action i put the code in the model, using callbacks:
before_save do |rec|
if !rec.new_record?
attrb = rec.attributes.delete_if{|k, v| ["id"].include? k }
Book.create(attrb)
rec.restore_attributes
rec.year = rec.year + 2 # some custom change
true
end
end
I keep all attributes unless the 'id' (otherwise i get an error) for create a new record with the new attributes.
Then i restore the attributes of the existing record. I do some custom change before saving.
I am rather new with Rails but this seems pretty straightforward. As you mention the user is 'updating" an invoice, your controller view has probably been passed all the data available to the user for further change.
When submitting the form, your update action can easily update the current record data, as well as creating a new one on top of this
Though as it is automated, you need to make clear:
if a new invoice record is created each time an invoice record is
updated (thi can create a lot of copies of the same invoice)
how you make the old record an archive to avoid duplicates
can the 'additional" amendments be automated and easily processed through an algorithm...
Nested attributes made things a bit tricky. So in order to create new instances I had to use the dup method for both the resource and its nested items.
Generally, it is advisable to keep the controllers slim and make the models fat. Nevertheless, I have decided to include this code into my Invoices controller:
def revise_save
#contact = Contact.find(params[:contact_id])
#invoice = #contact.invoices.find(params[:invoice_id])
#invoice_old = #invoice.dup
#invoice.invoice_items.each do |item|
#invoice_old.invoice_items << item.dup
end
#invoice.datum = DateTime.now.to_date
# archive old invoice
# #invoice_old. ...
#invoice_old.save
# make old new invoice
#invoice.datum = Time.now
# ...
#invoice.update(invoice_params)
redirect_to invoices_path
end
Note that in this solution the currently edited (original) invoice becomes the new invoice, the old one is paradoxically created anew.
Thanks to #iwan-b for pointing me in the right direction.

How to pass manytomany PKs to post or put

class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.PrimaryKeyRelatedField(many=True, queryset=Track.objects.all(), )
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
what is the format for adding multiple tracks
tracks is a manytomany field
tried array, comma separated but no luck
If I pass
track = "Track1"
where "Track1" is the primary key of Track 1
How to add ['Track1', 'Track2']
Actual code
class TreatmentTemplateSerializer(serializers.ModelSerializer):
icds = serializers.PrimaryKeyRelatedField(read_only=False, many=True, queryset=ICD_10.objects.all())
class Meta:
model = Treatment_template
Screenshot 1
Postman supports array in above format??
Screenshot 2
Screenshot 3
Sending plain JSON objects
I would suggest testing complex request data (including arrays or nested objects) by directly sending JSON rather than form-data or x-www-form-urlencoded. To do this click on raw and paste your JSON object there.
To get a well-formatted JSON object to start with I usually first issue a GET request for a resource that already exists. Then I can just copy the response, change the request method to PUT, click the raw button and paste the json. Then I can start modifying the object and test the endpoint.
In the example above, does the following work?
{
"uuid": "the-long-uuid-here",
"icds": [
"A00",
"A001"
]
}
Update: Put multiple m2m ids with x-www-form-urlencoded
As I wasn't completely happy with not providing an alternative I tested a bit more (with the latest Postman which looks differently).
You can pass multiple values using x-www-form-urlencoded. To do that, add multiple rows with the same label icds and one value at a time.
Notice that I tested it with an endpoint that provides books, which would be icds in your use case. The data in the screenshot will be transmitted as books=1&books=3&last_name=foobar which gets correctly picked up by the DRF endpoint.
Screenshot Postman

Django: How to access the model id's within an AJAX script?

I was wondering what is the correct approach,
Do I create HiddenInput fields in my ModelForm and from the
View I pass in the primaryKey for the models I am about to edit into
the hiddenInput fields and then grab those hiddenInput fields from
the AJAX script to use it like this?
item.load(
"/bookmark/save/" + hidden_input_field_1,
null,
function () {
$("#save-form").submit(bookmark_save);
}
);
Or is there is some more clever way of doing it and I have no idea?
Thanks
It depends upon how you want to implement.
The basic idea is to edit 1. you need to get the existing instance, 2. Save provided information into this object.
For #1 you can do it multiple ways, like passing ID or any other primary key like attribute in url like http://myserver/edit_object/1 , Or pass ID as hidden input then you have to do it through templates.
For #2, I think you would already know this. Do something like
inst = MyModel.objects.get(id=input_id) # input_id taken as per #1
myform = MyForm(request.POST, instance=inst)
if myform.is_valid():
saved_inst = myform.save()
I just asked in the django IRC room and it says:
since js isn't processed by the django template engine, this is not
possible.
Hence the id or the object passed in from django view can't be accessed within AJAX script.