DRF: Set ChoiceField default programmatically from DB query - django

I asked a similar question here about setting the default value of a TextChoices field on a model. Now I'm taking it to the next level.
I've moved the choices settings from the model to the serializer ChoiceField. The site is Django/DRF/django_tenants backend with Vue frontend. I want the front/backends to be using the same set of choices and, just as important, the same default values. So I created an OptionGroup table. Here are two sample rows from that table (some options omitted):
{
"results": {
"id": 1,
"name": "payment_method",
"defined_in": "option_table",
"default_option": "5",
"options": [
{
"id": 2,
"name": "Bank Transfer",
"value": "2"
},
{
"id": 5,
"name": "Credit Card",
"value": "5"
},
{
"id": 8,
"name": "PayPal",
"value": "8"
}
]
}
}
{
"results": {
"id": 3,
"name": "invoice_type",
"defined_in": "class",
"app_label": "invoices",
"choices_class": "InvoiceType",
"default_option": "standard",
"options": [
{
"name": "Standard",
"value": "standard"
},
{
"name": "Retainer",
"value": "retainer"
},
{
"order": 1,
"name": "Estimate",
"value": "estimate"
}
]
}
}
The first one (defined_in = "option_table") has its options defined in a related Option model. The second one has its options defined in a subclass of TextChoices in the backend code. In addition to keeping the front/backend in sync for options and default values, this will also allow users to set which option for each select list field they want as the default value. Note the default_option field above.
I created a class, extended from the ChoiceField class (from DRF), and added logic to the __init__() method to get the default value from the OptionGroup model and set it for the serializer field being defined.
class CustomChoiceField(serializers.ChoiceField):
def __init__(self, choices, **kwargs):
option_group = kwargs.pop('option_group', None)
if option_group and 'default' not in kwargs:
group = OptionGroup.objects.filter(name__iexact=option_group)
if group and group.default_option:
kwargs['default'] = group.default_option
super().__init__(choices, **kwargs)
And this is how it is being used:
type = CustomChoiceField(
choices=choices.InvoiceType.choices,
option_group='invoice_type',
)
The problem is that the active schema at that point is "public" instead of the actual tenant schema. It seems the __init__() for my custom class is being executed too early in the request process - before django_tenants has connected to the proper schema.
Does anyone have a suggestion as to how this can be accomplished, or is what I'm trying to do just not possible?

Related

How to apply filter in loopback while including another model via "hasMany" relation?

I am using loopback 3. I have two models project and project members.
Project has "hasMany" relation with project members.
So far, I use http://localhost:3000/api/v1/Projectsfilter[include]=projectMember which gives me result like below :-
{
"projectName": "project 1 ",
"clientNames": {},
"projectShortCode": "string",
"projectMember": [
{
"projectId": 1,
"userId": 1,
"id": 1
},
"projectName": "project 2",
"clientNames": {},
"projectShortCode": "string",
"projectMember": [
{
"projectId": 1,
"userId": 2,
"id": 2
}
}
How do I apply filter on api that I get only those project in result which has userId = 1 ?
I'm afraid you can't filter projects by the related model property.
But what you could do after the api call is to filter your array, eg. you can call something like this:
api.makeRequest(projectsURL).filter(project => project.userId === 1);
Here you can find more info about that issue:
https://github.com/strongloop/loopback/issues/1754
Loopback Filter Based On Related Model Properties

How can I get the attribute value based on sibling attribute value from a json response?

This is my response.
[
{
"id": 123,
"name": "text1"
},
{
"id": 456,
"name": "text2"
},
{
"id": 789,
"name": "text3"
}
]
I can just provide the name value and want to get back the id attribute. I am using rest assured. I can create a map and then get it accordingly but searching for solutions like jsonPath().get(id where name ="text2"). Just thinking if anything can be done like that.
You can use conditions like .find{it.name=='text2'}.id

Loopback framework always expecting the input field names as lowercase

We are implementing the Database connector with Loopback framework. Database fields are case-insensitive. Loopback framework creating the model with all table fields and properties as lowercase characters. When we invoke create or update operation with field names as uppercase, it's throwing the input validation errors.
{
"error": {
"name": "ValidationError",
"status": 422,
"message": "The `TEST5` instance is not valid. Details: `name` can't be blank (value: undefined).",
"statusCode": 422,
"details": {
"context": "TEST5",
"codes": {
"name": [
"presence"
]
},
"messages": {
"name": [
"can't be blank"
]
}
},
"stack": "ValidationError: The `TEST5` instance is not valid. Details: `name` can't be blank (value: undefined).\n at ..node_modules\\loopback-datasource-juggler\\lib\\dao.js:211:16\n at ModelConstructor. (..node_modules\\loopback-datasource-juggler\\lib\\validations.js:462:11)\n
}
}
Use .observe with "before save" hook. Then loop through properties converting to lower case. Before save with observe hits before validation too

Ember - Only update fields returned in response JSON

we would like to add lazy loading functionality to our ember project, but it looks like ember will always override fields not returned by the response JSON with NULL. First I get a list of users:
GET https://example.com/users
{
"users": [
{
"id": 1,
"name": 'user1',
"email": 'email#user1.com',
"images": [],
"posts": []
},
{
"id": 2,
"name": 'user2',
"email": 'email#user2.com',
"images": [],
"posts": []
},
{
"id": 3,
"name": 'user3',
"email": 'email#user3.com',
"images": [],
"posts": []
},
]
}
This provides a minimal set of user information, with two empty hasMany relations "images" and "posts".
Now, if somebody want to see the users posts or images he would click a button which triggers the lazy loading:
GET https://example.com/userImages/1
{
"user": {
"id": 1,
"images": [1,2,3,4]
},
"images": [
{
"id": 1,
"name": "image1",
"path" "path/to/img1/"
},
{
"id": 2,
"name": "image2",
"path" "path/to/img2/"
},
{
"id": 3,
"name": "image3",
"path" "path/to/img3/"
},
{
"id": 4,
"name": "image4",
"path" "path/to/img4/"
}
]
}
To reduce traffic to a minimum, only the newly loaded information is included. After the adapter has deserialzed and pushed the new data to the store, all fields from User1 which are not included in the payload (name, email) are set to NULL in the ember store (tested with store.pushPayload('model', payload)).
Is there a possibility to update only incoming data? Or is there a common best practice to handle such a case?
Thanks in advance for your help
EDIT:
One possibility would be to extend the ember-data "_load()" function with the block
for (var key in record._data) {
var property = record._data[key];
if( typeof(data[key]) == 'object' && data[key] == null ) {
data[key] = property;
}
}
But this is the worst possible solution I can imagine.
I think what you want is the store's update method. It's like push (or pushPayload), except that it only updates the data that you give it.
Your property returns a promise and that promise returns whatever came back from the server.
foobar: function() {
return this.store.find('foobar');
}
When the promise resolves, you have two versions of the data, the one already rendered in the client (dataOld) and the one that just returned from the backend (dataNew). To update the client without removing what hasn't change, you have to merge the old and the new. Something along the lines of:
foobar: function() {
var dataOld = this.get('foobar');
return this.store.find('foobar').then(function(dataNew) {
return Ember.$.merge(dataOld, dataNew);
});
}

Is it possible to set the django-tastypie objects key?

By default, when using django-tastypie and fetching a resource list, the response is of the format:
{
"meta": {
"limit": 20,
"next": null,
"offset": 0,
"previous": null,
"total_count": 3
},
"objects": [{
"body": "Welcome to my blog!",
"id": "1",
"pub_date": "2011-05-20T00:46:38",
"resource_uri": "/api/v1/entry/1/",
"slug": "first-post",
"title": "First Post",
"user": "/api/v1/user/1/"
},
...
]
}
I've dug into the documentation and looked & looked, but I can't seem to find any kind of meta option or setting to change the "objects" key to actually describe the returned items. For example, let's say I have list of locations in one api call and a list of people in another. I'd like to be able to differentiate the key to "locations" and "people". The real reason for this is because I'm using RestKit on iOS and want to be able to set up multiple mappings.
The Resource hooks alter_* can be used to alter the structure of the data.
An example Resource using 'locations' would be:
class MyLocationsResource(ModelResource):
def alter_list_data_to_serialize(self, request, data):
data['locations'] = data['objects']
del data['objects']
return data
def alter_deserialized_list_data(self, request, data):
data['objects'] = data['locations']
del data['locations']
return data