i am using fastapi with tortoise orm and when i want to add a cart i get this error
error
if value and not value._saved_in_db:
AttributeError: 'int' object has no attribute '_saved_in_db'
models
class Cart(BaseModel):
user = fields.ForeignKeyField('models.User', related_name='user_cart')
product = fields.ForeignKeyField(
'models.Product', related_name='product_cart')
quantity = fields.IntField(default=0)
class Meta:
table = 'carts'
ordering = ('-created',)
schemas
class CartCreate(BaseModel):
product_id: int
quantity: int = Field(..., ge=0, le=10)
class Cart(BaseModel):
id: int
class Config:
orm_mode = True
routes
#router.post('/create', status_code=status.HTTP_201_CREATED)
async def create_cart(
cart: CartCreate,
user: User = Depends(get_current_user)
) -> CartSchema:
cart_obj = await Cart.create(
user=user.id,
product=cart.product_id,
quantity=cart.quantity
)
return CartSchema.from_orm(cart_obj)
what should i do?
Related
I am stuck here:
I have an interface Field which has a name and a value of some unknown type.
interface Field<T> {
name: string;
value: T;
}
I then have a function form, which takes any amount of Field's as rest parameters and returns the data they hold.
function form<T extends Field<unknown>[]>(
...fields: T
): { [k in T[number]['name']]: T[number]['value'] } {
let data = {};
fields.forEach((field) => (data[field.name] = field.value));
return <{ [k in T[number]['name']]: T[number]['value'] }>data;
}
It look like this is action:
const age: Field<number> = { name: 'age', value: 30 };
const sex: Field<string> = { name: 'sex', value: 'men' };
const data = form(age, sex);
// { age: 30, sex: 'men' }
In this example the types of age and sex are just the union of all fields.
data.age; // number | string
data.sex; // number | string
What i want is data to be of type:
const data: { age: number, sex: string } = form(age, sex);
But this returns the error ts(2451).
What does the return type of form need to be.
Is this even possible?
(I'm using typescript version 4.9.3, the latest as of 2022-11-29)
[Edit 2022-11-30]: add Link to working example
typescriptlang.org/play
Your Field should have a ganegic on its name also
interface Field<K extends string, V> {
name: K;
value: V;
}
function ensureField<K extends string, V>(field: Field<K, V>) {
return field;
}
type FieldListToRecord<List extends Field<any, any>[], O extends {} = {}> =
| List extends [infer F extends Field<any, any>, ...infer L extends Field<any, any>[]] ?
FieldListToRecord<L, O & (
F extends Field<infer K, infer V> ? { [k in K]: V }
: never
)>
: { [K in keyof O]: O[K] }; // <- Pure<T>
function form<T extends Field<any, any>[]>(
...fields: T
): FieldListToRecord<T> {
return Object.fromEntries(
fields.map(({ name, value }) => [name, value])
);
}
const age = ensureField({ name: 'age', value: 30 });
// ^?
const sex = ensureField({ name: 'sex', value: 'men' });
// ^?
const data = form(age, sex);
// ^?
// { age: 30, sex: 'men' }
Playground
I have an ASP.NET Core Web API and a React client. I'm trying to build admin dashboard with React-Admin. My problem is when I receive the data from server, my object are with property Id (uppercase), then in console I'm getting an error
The response to 'getList' must be like { data : [{ id: 123, ...}, ...] }, but the received data items do not have an 'id' key
I tried making new test class with property id (lowercase) in my server and then the problem is gone.
How can I fix this issue?
This is my test class and its working.
public class CityModel
{
public string id { get; set; }
public string Name { get; set; }
}
[HttpGet("Cities")]
public CityModel[] GetCities()
{
var city1 = new CityModel()
{
id = "ahsxge",
Name = "Berlin"
};
var city2 = new CityModel()
{
id = "axhdagw",
Name = "London"
};
var list = new List<CityModel>();
list.Add(city1);
list.Add(city2);
Response.Headers.Add("Access-Control-Expose-Headers", "X-Total-Count");
Response.Headers.Add("X-Total-Count", list.Count.ToString());
return list.ToArray();
}
This is my component in react :
const AppAdmin = () => {
const jwt = localStorage.getItem("jwt");
const httpClient = (url, options = {}) => {
options.user = {
authenticated: true,
token: 'Bearer ' + jwt
};
return fetchUtils.fetchJson(url, options);
};
const dataProvider = jsonServerProvider('https://localhost:44366/api', httpClient);
dataProvider.getList('Cities/Cities', {
pagination: { page: 1, perPage: 15 },
sort: { field: 'Name', order: 'ASC' },
})
.then(response => console.log(response));
return (
<Admin dataProvider={dataProvider}>
<Resource name='Cities/Cities' list={CitiesList} />
</Admin>
)
}
export default AppAdmin
You can configure the json converter to use camelCase serialization int the ConfigureServices method in the Startup.cs file the following way:
services
.AddControllers()
.AddJsonOptions(opts =>
{
opts.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
})
This way you can use PascalCase properties in your c# code (which you should do), but your client will recieve camelCase json properties.
When trying to implement elasticsearch (v7.9.3) via the fos_elastica-bundle (v6.0.0) into my Symfony (v5.3.10) - App with api_platform (v2.6.6), I keep on getting this error:
"{"error":"no handler found for uri [//posts/_doc/_search] and method [POST]"}",
My api_platform.yaml reads:
api_platform:
[...]
elasticsearch:
hosts: [ '%env(ELASTICSEARCH_URL)%' ]
mapping:
App\Document\Post:
index: posts
and my fos_elastica.yaml:
fos_elastica:
clients:
default: { url: '%env(ELASTICSEARCH_URL)%' }
indexes:
posts:
properties:
id:
"type": "keyword"
source: ~
title: ~
description: ~
body: ~
children: ~
tags: ~
originalContent: ~
persistence:
driver: mongodb
model: App\Document\Post
By debugging the fos-elastica Bundle, I found out that the Elastica-Connector correctly triggers a [POST]-Request to "/posts/_doc/_search" with this request body:
{"sort":[{"id":{"order":"asc"}}],"query":{"match_all":{}},"size":30,"from":0}
If I use the Kibana Dev Tools Console and trigger an identical request
POST /posts/_doc/_search
{"sort":[{"id":{"order":"asc"}}],"query":{"match_all":{}},"size":30,"from":60}
I do get results from elasticsearch as expected:
#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
"took" : 12,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3082,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "posts",
"_type" : "_doc",
[...]
Apart from the deprecation notice, everything seems fine.
Does anyone have an idea why the api_platform integration of the fos_elastica-bundle does not work as expected and keeps on returning the "no handler found"-error message?
I have now helped myself by creating a custom ApiResource - filter
#[ApiFilter(FulltextFilter::class, arguments: ['index' => 'post'], properties: ['body','description','tag'])]
My custom filter implements ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\FilterInterface, directly communicates with the ElasticSearch server, sends a query to search the specified index (posts) and adds another match()-directive to the aggregationBuilder with a set of IDs matching the original search:
<?php
declare(strict_types=1);
namespace App\Filter;
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\FilterInterface;
use Doctrine\ODM\MongoDB\Aggregation\Builder;
use Elastica\Result;
use Elastica\Client;
use Elastica\Query;
use Symfony\Component\PropertyInfo\Type;
/**
* Filter the collection by given properties.
*
*/
final class FulltextFilter implements FilterInterface
{
protected $index = '';
protected $properties = [];
protected $client;
protected $searchParameterName;
protected $maxResultsParameterName;
const DEFAULT_MAX_RESULTS = 200;
public function __construct(Client $client, string $index = '', string $maxResultsParameterName = 'amount', string $searchParameterName = 'query', array $properties = []) {
$this->index = $index;
$this->properties = $properties;
$this->client = $client;
$this->searchParameterName = $searchParameterName;
$this->maxResultsParameterName = $maxResultsParameterName;
}
public function getFilteredIds($searchterm, $index = null, $properties = null, $maxResults = null) {
$matches = [];
if (is_null($properties)) {
$properties = array_keys($this->properties);
}
foreach ($properties as $propertyName) {
array_push($matches, ['match'=>[$propertyName => $searchterm]]);
}
$queryObject = ['query' => ['bool' => ['should' => $matches]]];
$queryObject['size'] = (int) $maxResults >0 ? (int) $maxResults : self::DEFAULT_MAX_RESULTS;
$query = new Query();
$response = $this->client->getIndex($index ?? $this->index)
->search($query->setRawQuery($queryObject))
->getResults();
return array_map(function(Result $result) {return $result->getHit()['_source']['id'];}, $response);
}
public function apply(Builder $aggregationBuilder, string $resourceClass, string $operationName = null, array &$context = [])
{
$maxResults = $context['filters'][$this->maxResultsParameterName] ?? null;
$searchterm = $context['filters'][$this->searchParameterName] ?? false;
if ($searchterm !== false) {
$aggregationBuilder->match()->field('id')->in($this->getFilteredIds($searchterm, null, null, $maxResults));
}
}
public function getDescription(string $resourceClass): array
{
return [];
}
}
This solution might not be as elegant as using the ElasticSearch-Connector natively provided by api_platform, but it is fairly performant and it works.
However, if someone comes up with a solution to fix the depicted ES-Connector issue with api_platform, please feel free to share it.
The problem is that, FOS Elastica requires an ES URL with an ending slash. But Api Platform requires a URL without ending slash.
We usually define the URL in .env file and then recall it in config files.
To solve the problem, we could define the URL in .env without endling slash and add the slash to the FOS Elastica config.
# .env
###> friendsofsymfony/elastica-bundle ###
ELASTICSEARCH_URL=http://localhost:9200
###< friendsofsymfony/elastica-bundle ###
# config/packages/api_platform.yaml
api_platform:
elasticsearch:
enabled: true
hosts: [ '%env(ELASTICSEARCH_URL)%' ]
# config/packages/fos_elastica.yaml
fos_elastica:
clients:
default: { url: '%env(ELASTICSEARCH_URL)%/' }
I have this helper function in my reducer, which has the given state:
type CustomerCollection = { [number]: Customer }
type CustomerState = {
+customers: ?CustomerCollection,
+newItem: ?(Customer | Review),
+searchResults: ?(Customer[]),
+error: ?string,
+isLoading: boolean
};
function customerWithReview(review: Review): Customer {
const id: number = review.customerId;
const oldCustomer: Customer = state.customers[id];
const newReviews: Review[] = [review, ...oldCustomer.reviews];
return Object.assign(oldCustomer, { reviews: newReviews });
}
I get a Flow error on the id of const oldCustomer: Customer = state.customers[id]; saying Cannot get state.customers[id] because an index signature declaring the expected key/value type is missing in null or undefined.
This is happening because of the nullable/optional ?CustomerCollection type of state.customers.
I can silence the error by making sure customers isn't null:
if (state.customers) {
const oldCustomer: Customer = state.customers[id];
const newReviews: Review[] = [review, ...oldCustomer.reviews];
return Object.assign(oldCustomer, { reviews: newReviews });
}
But then the problem just goes up the chain because I don't have anything to return from the function.
I can certainly expand it to:
function customerWithReview(review: Review): Customer {
if (!state.customers) {
return new Customer();
} else {
const id: number = review.customerId;
const oldCustomer: Customer = state.customers[id];
const newReviews: Review[] = [review, ...oldCustomer.reviews];
return Object.assign(oldCustomer, { reviews: newReviews });
}
}
But in actual practice, the action that gets us to this branch of the reducer will never be called if state.customers is null, and we'd never return new Customer() and would have no use for it if we did. state.customers is nullable in order to tell the difference between "we haven't fetched the customers yet (state.customers == null)" and "we've fetched the customers but there are none (state.customers == {}).
It would be a lot easier if I could just assert that state.customers would always exist in these cases, which in Swift I would do with force-unwrapping:
const oldCustomer: Customer = state.customers![id];
Can I do anything like this with Flow?
Or, given that only my GET_CUSTOMERS_FAILURE action would ever deal with state.customers == null, is there some other way to restructure my reducer so that this is a little easier? An entirely separate fetchReducer that is has a nullable customer collection while the rest of the actions fall under a different reducer?
You can use invariant function (Check that it works here):
type Customer = { id: number, reviews: Array<Review> };
type Review = { customerId: number };
type CustomerCollection = { [number]: Customer }
type CustomerState = {
+customers: ?CustomerCollection,
+newItem: ?(Customer | Review),
+searchResults: ?(Customer[]),
+error: ?string,
+isLoading: boolean
};
declare var state: CustomerState;
declare function invariant(): void;
function customerWithReview(review: Review): Customer {
const id: number = review.customerId;
invariant(state.customers, 'No customers and I don\'t know why');
const oldCustomer: Customer = state.customers[id];
const newReviews: Review[] = [review, ...oldCustomer.reviews];
return Object.assign(oldCustomer, { reviews: newReviews });
}
You can implement it somewhere in your project and import when necessary.
You can implement it like this:
export function invariant<T>(value: ?T, falsyErrorMessage: string, errorParams?: Object): void {
if (!value) {
log.error(falsyErrorMessage, errorParams || {});
throw new Error(INVARIANT_ERROR_MESSAGE);
}
}
Unfortunately, the name of the function is hard-coded in flow.
Alternative variant is just to add an if and to throw an error in your customerWithReview function directly.
Good afternoon everyone, I am trying to upload an image to firebase and display back on a cell..I have just about all the content working except the image (i cant get rid of the error).
Here is the error I am getting
Cannot invoke initializer for type 'Posts' with an argument list of type '(postImageStringUrl: String, content: String!, postId: String)'
//[Save Image]
// Create data in the server
let data = UIImageJPEGRepresentation(self.addedImage.image!, 0.5)
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
let postId = "\(Auth.auth().currentUser!.uid)\(NSUUID().uuidString)"
// Create a reference to the file you want to upload
let imagePath = "postImages\(postId)/postPic.jpg"
storageRef.child(imagePath).putData(data!, metadata: metadata) { (metadata, error) in
if error == nil {
let postRef = self.databaseRef.child("posts").childByAutoId()
let post = Posts(postImageStringUrl: String (describing: metadata!.downloadURL()), content: descriptionTextView.text, postId: postId)
postRef.setValue(post.toAnyObject())
}else{
print(error.debugDescription)
}
}
//[Save Image]
Here is my postViewController
import Foundation
import Firebase
import FirebaseDatabase
import FirebaseStorage
struct Posts {
var postImageStringUrl: String!
var department: String!
var content: String!
var username: String!
var postId: String!
var ref: DatabaseReference?
var key: String!
init(postImageStringUrl: String, department: String, content: String, username: String,postId: String, key: String = ""){
self.postImageStringUrl = postImageStringUrl
self.department = department
self.content = content
self.username = username
self.postId = postId
self.key = key
self.ref = Database.database().reference()
}
init(snapshot: DataSnapshot){
let snapshotValue = snapshot.value as! NSMutableDictionary
self.postImageStringUrl = snapshotValue["postImageStringUrl"] as! String
self.department = snapshotValue["department"] as! String
self.content = snapshotValue["content"] as! String
self.username = snapshotValue["username"] as! String
self.postId = snapshotValue["postId"] as! String
self.key = snapshot.key
self.ref = snapshot.ref
}
func toAnyObject() -> [String: AnyObject] {
return ["postImageStringUrl": postImageStringUrl as AnyObject, "department": department as AnyObject,"content": content as AnyObject,"username": username as AnyObject, "postId": postId as AnyObject]
}
}
Any help will be greatly appreciated...Ty
Your Posts init is
init(
postImageStringUrl: String,
department: String,
content: String,
username: String,
postId: String,
key: String = "")
and it appears you are trying to initialize it with
let post = Posts(
postImageStringUrl: String (describing: metadata!.downloadURL()),
content: descriptionTextView.text,
postId: postId)
Basically just missing a couple of parameters in the initialization; department, username