Graphene-Python documentation on clients view - metadata

The description property on GraphQL's schema elements can be viewed by the client. For example, GraphQL shows the description value for a field object in the type-ahead dropdown that lists fields available inside a selection set. This same description appears on the documentation section. Can this type of metadata documentation be added through graphene-gae? My set up:
models.py:
class Article(ndb.Model):
headline = ndb.StringProperty()
author_key = ndb.KeyProperty(kind='Author')
created_at = ndb.DateTimeProperty(auto_now_add=True)
import graphene
from graphene_gae import NdbObjectType
Schema.py:
class ArticleType(NdbObjectType):
class Meta:
model = Article
class Query(graphene.ObjectType):
articles = graphene.List(ArticleType)
#graphene.resolve_only_args
def resolve_articles(self):
return Article.query()
schema = graphene.Schema(query=QueryRoot)

I can add descriptions like this:
headline = ndb.StringProperty(description='Add description here!')
Super Easy!

Related

How to make use of the user defined View to pipe data into application with flutter/drift(moor)

I declared some Views following the example in the drift documentation besides database table definitions and managed to go through the generation process. After then I was quite confused as to the usage of the abstract View classes, which I could neither instantiate to make query nor incorporate it into query definitions(get or watch).
abstract class TestingRemoteSignalView extends View {
TestingRemoteSignal get testingRemoteSignal;
Bay get bay;
RemoteSignal get remoteSignal;
Expression<String> get description => bay.name + remoteSignal.signalName;
#override
Query as() {
return select([
testingRemoteSignal.id,
bay.name,
description,
testingRemoteSignal.passed,
testingRemoteSignal.skipped,
testingRemoteSignal.touched,
testingRemoteSignal.memo,
]).from(testingRemoteSignal).join([
innerJoin(bay, testingRemoteSignal.bay.equalsExp(bay.id)),
innerJoin(
remoteSignal, testingRemoteSignal.signal.equalsExp(remoteSignal.id))
]);
}
}
What is the use of these View classes and how to make queries out of them? Maybe something like:
final query = select(TestingRemoteSignalView)..where((t) => t.passed.isEquals(true));
query.watch();
This page in the Drift documentation has a section on views here.
I found this video on Youtube quite helpful as well.
Once you have created your view code as you have in your question, you need to add the view to database definition as follows (from the documentation):
#DriftDatabase(tables: [Todos, Categories], views: [CategoryTodoCount])
class MyDatabase extends _$MyDatabase {
Then you need to delete and rebuild your '.g.dart' file.
You should then be able to access the view in a query like any other table. Here is an example from my own code:
View definition
abstract class FrequencyView extends View {
Frequency get frequency;
Instrument get instrument;
Range get range;
#override
Query as() => select([
frequency.id,
frequency.type,
frequency.start,
frequency.end,
instrument.iname,
range.rname
]).from(frequency).join([
innerJoin(instrument, instrument.id.equalsExp(frequency.instrumentID))
]).join([innerJoin(range, range.id.equalsExp(frequency.rangeID))]);
}
// FrequencyView declared in DraftDatabase declaration below...
#DriftDatabase(tables: [Frequency, Range, Instrument], views: [FrequencyView])
class MyDatabase extends _$MyDatabase {
// we tell the database where to store the data with this constructor
MyDatabase() : super(_openConnection());
// you should bump this number whenever you change or add a table definition.
// Migrations are covered later in the documentation.
#override
int get schemaVersion => 1;
}
As an aside, I had fields with the same name in different tables ('name'), which caused errors in the .g.dart file once I had rebuilt it. I wasn't sure if you can alias column names in a view so I just gave them all unique names.
View select query
import 'package:drift/drift.dart' as drift;
Future<List<FrequencyViewData>> _getFrequencyPlus(MyDatabase db) async {
List<FrequencyViewData> values = await (db.select(db.frequencyView)
..orderBy([(t) => drift.OrderingTerm(expression: t.start)]))
.get();
return values;
}
This query returns a full set of data. I assume you can add "where" clauses to this just like a standard select clause on a single table to get partial returns.

How to extend django's default User in mongodb?

I'm using mongodb as database and trying to extend the django's inbuilt user model.
here's the error I'm getting:
django.core.exceptions.ValidationError: ['Field "auth.User.id" of model container:"<class \'django.contrib.auth.models.User\'>" cannot be of type "<class \'django.db.models.fields.AutoField\'>"']
Here's my models.py:
from djongo import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.EmbeddedField(model_container=User)
mobile = models.PositiveIntegerField()
address = models.CharField(max_length=200)
pincode = models.PositiveIntegerField()
Using EmbeddedField is not a good idea, because it will duplicate user data in the database. You will have some user in the Users collection and the same data will be embedded in the Profile collection elements.
Just keep the user id in the model and query separately:
class Profile(models.Model):
user_id = models.CharField() #or models.TextField()
mobile = models.PositiveIntegerField()
address = models.CharField(max_length=200)
pincode = models.PositiveIntegerField()
It is simple as defined in the documentation.
So, first, use djongo models as the model_container, and I suppose the User model is the Django model, not the djongo model.
And the second thing, make your model_cotainer model abstract by defining in the Meta class as given below.
from djongo import models
class Blog(models.Model):
name = models.CharField(max_length=100)
class Meta:
abstract = True
class Entry(models.Model):
blog = models.EmbeddedField(
model_container=Blog
)
headline = models.CharField(max_length=255)
Ref: https://www.djongomapper.com/get-started/#embeddedfield

EmbeddedDocumentSerializer runs query for every ReferenceField

I have following models and serializer the target is when serializer runs to have only one query:
Models:
class Assignee(EmbeddedDocument):
id = ObjectIdField(primary_key=True)
assignee_email = EmailField(required=True)
assignee_first_name = StringField(required=True)
assignee_last_name = StringField()
assignee_time = DateTimeField(required=True, default=datetime.datetime.utcnow)
user = ReferenceField('MongoUser', required=True)
user_id = ObjectIdField(required=True)
class MongoUser(Document):
email = EmailField(required=True, unique=True)
password = StringField(required=True)
first_name = StringField(required=True)
last_name = StringField()
assignees= EmbeddedDocumentListField(Assignee)
Serializers:
class MongoUserSerializer(DocumentSerializer):
assignees = AssigneeSerializer(many=True)
class Meta:
model = MongoUser
fields = ('id', 'email', 'first_name', 'last_name', 'assignees')
depth = 2
class AssigneeSerializer(EmbeddedDocumentSerializer):
class Meta:
model = Assignee
fields = ('assignee_first_name', 'assignee_last_name', 'user')
depth = 0
When checking the mongo profiler I have 2 queries for the MongoUser Document. If I remove the assignees field from the MongoUserSerializer then there is only one query.
As a workaround I've tried to use user_id field to store only ObjectId and changed AssigneeSerializer to:
class AssigneeSerializer(EmbeddedDocumentSerializer):
class Meta:
model = Assignee
fields = ('assignee_first_name', 'assignee_last_name', 'user_id')
depth = 0
But again there are 2 queries. I think that the serializer EmbeddedDocumentSerializer fetches all the fields and queries for ReferenceField and
fields = ('assignee_first_name', 'assignee_last_name', 'user_id')
works after the queries are made.
How to use ReferenceField and not run a separate query for each reference when serializing?
I ended up with a workaround and not using ReferenceField. Instead I am using ObjectIdField:
#user = ReferenceField("MongoUser", required=True) # Removed now
user = ObjectIdField(required=True)
And changed value assignment as follows:
- if assignee.user == MongoUser:
+ if assignee.user == MongoUser.id:
It is not the best way - we are not using ReferenceField functionality but it is better than creating 30 queries in the serializer.
Best Regards,
Kristian
It's a very interesting question and I think it is related to Mongoengine's DeReference policy: https://github.com/MongoEngine/mongoengine/blob/master/mongoengine/dereference.py.
Namely, your mongoengine Documents have a method MongoUser.objects.select_related() with max_depth argument that should be large enough that Mongoengine traversed 3 levels of depth: MongoUser->assignees->Assignee->user and cached all the related MongoUser objects for current MongoUser instance. Probably, we should call this method somewhere in our DocumentSerializers in DRF-Mongoengine to prefetch the relations, but currently we don't.
See this post about classical DRF + Django ORM that explains, how to fight N+1 requests problem by doing prefetching in classical DRF. Basically, you need to override the get_queryset() method of your ModelViewSet to use select_related() method:
from rest_framework_mongoengine.viewsets import ModelViewSet
class MongoUserViewSet(ModelViewSet):
def get_queryset(self):
queryset = MongoUser.objects.all()
# Set up eager loading to avoid N+1 selects
queryset.select_related(max_depth=3)
return queryset
Unfortunately, I don't think that current implementation of ReferenceField in DRF-Mongoengine is smart enough to handle these querysets appropriately. May be ComboReferenceField will work?
Still, I've never used this feature yet and didn't have enough time to play with these settings myself, so I'd be grateful to you, if you shared your findings.

How do I map Grails Searchable plugin across more than 2 domain objects?

I'm using the Searchable plugin in my Grails application, but am having trouble getting it to map across more than 2 domain objects while returning valid search results. I've looked through the Searchable plugin documentation, but cannot find the answer to my question. Here's a very basic example of the domains I have:
class Article {
static hasMany = [tags: ArticleTag]
String title
String body
}
class ArticleTag {
Article article
Tag tag
}
class Tag {
String name
}
Ultimately what I'm looking to do is be able to find articles by searching their titles, body and associated tags. The titles and tags would be boosted as well.
What's the proper way to map these classes to meet the desired results?
There is probably another approach, but this is the simple approach I used in my application. I added a method to the domain object to get all of string values from the tags and add them to the index with the Article object.
This allows me to just search the Article domain object and get everything I need
class Article {
static searchable = {
// don't add id and version to index
except = ['id', 'version']
title boost: 2.0
tag boost:2.0
// make the name in the index be tag
tagValues name: 'tag'
}
static hasMany = [tags: ArticleTag]
String title
String body
// do not store tagValues in database
static transients = ['tagValues']
// create a string value holding all of the tags
// this will store them with the Article object in the index
String getTagValues() {
tags.collect {it.tag}.join(", ")
}
}

row specific class

How do I create a Zend_Db_Table which returns a different class for each row.?
Example
UserTable has id,name and type
Type contains class names (admin,client,etc...)
The classes admin, client are all subclasses of user
If I call fetch I need to get a admin or client object depending on the corresponding value in the db.
class Your_Db_Table_Row extends Zend_Db_Table_Row_Abstract
{
}
class Your_Db_Table extends Zend_Db_Table_Abstract
{
protected $_rowClass = "Your_Db_Table_Row";
}
or
new Your_Db_Table(array("rowClass" => "Your_Db_Table_Row");
So whenever you get a rowset from your table subclass, the rows included in it will be your custom class.
Edit
To get a custom row based on a value, I would say extend the Zend_Db_Table_Rowset_Abstract class instead and override this method:
getRow(int $position, [bool $seek = false])
You'll also need to override the current method and perhaps some of the other SeekableIterator implemetations which actually creates a row class based on the _rowClass property. You might be able to set the _rowClass before current is called based on your data's row type.
You could instantiate a specific class in current and return it based on the type parameter.
Have you though about maybe just using composition instead? Say just passing in data to a new class if it's an admin type or something?