Pass array of links in mutation [graphene/python/graphql] - python

i'm a little bit confuses about using graphene.
I am using the example of mutations on https://www.howtographql.com/graphql-python/3-mutations/ , but here only the example is shown how to create ONE link. Now it is more realistic for me that you have a list of links or other objects that you pass to your backend and later database. Is there anyone who has already implemented such an example?

I have taken a different example from https://docs.graphene-python.org/en/latest/types/mutations/#inputfields-and-inputobjecttypes . Below code snippet should help you in creating multiple instances in a single mutation.
import graphene
from .models import Person
class PersonInput(graphene.InputObjectType):
name = graphene.String(required=True)
age = graphene.Int(required=True)
class PersonType(DjangoObjectType):
class Meta:
model = Person
class CreatePerson(graphene.Mutation):
class Arguments:
person_objects = graphene.List(PersonInput, required=True)
persons = graphene.List(PersonType)
def mutate(root, info, person_objects):
persons = list()
for person_data in person_objects:
person = Person.objects.create(
name=person_data.name,
age=person_data.age
)
persons.append(person)
return CreatePerson(persons=persons)
mutation:
createPerson(personObjects: [{name: "Danish Wani" age:28}, {name: "Wani Danish" age:29}]){
persons{
name
age
}
}

Related

How to get object_set in serializer from Many to Many?

I want to allow saving some specific field only if it responds to some statement. Let me explain.
models.py
class classe(models.Model):
name = models.CharField(max_length=191)
groups = models.ManyToManyField('Group')
persons = models.ManyToManyField('Person')
class Group(models.Model):
name = models.CharField(max_length=191)
persons = models.ManyToManyField('Person')
class Person:
name = models.CharField(max_length=191)
serializers.py
class GroupSerializer(serializers.ModelSerializer):
persons = PersonSerializer(many=True, read_only=True)
person_id = serializers.PrimaryKeyRekatedField(queryset=Person.objects.all(), write_only=True)
def update(self, instance, validated_data, **kwargs):
instance.name = validated_data.get('name', instance.name)
person_field = validated_data.get('person_id)
classe = instance.classe_set #This one doesn't work
person_classe = classe.persons.all() #This one too
if (person_field in person_classe):
instance.persons.add(person_field)
instance.save()
return instance
So, the person_field can be saved only if the person is in the actual classe.
Everything work fine, but the two commented lines don't, so can't access the if statement.
Does someone know how can I figure it out ?
Because Group and Classe are ManyToManyfield with each other; therefore a Group can have many Classe and a Classe can have many groups.
Therefore to get the list of classes of a group:
classes = list(mygroup.classe_set.all())
In your update function, I'm guessing you're trying to add the person to the group if the person is in the classes associated with that group. If yes, here is what you need:
# first get all the associated Classe, you need the '.all()'
# keep in mind that .all() gives you a queryset
classes = instance.classe_set.all()
for c in classes:
students = c.persons.all() # persons of a classe of this group
if students.filter(id=person_field.id).exists():
# if this person is in the persons of this classe of this group
# then we add this person to this group
instance.persons.add(person_field)
break # we only need to add it once, right?
Hope this helps!

Check if object has relation with other in ManyToMany field and aggregate field

I have a couple models as follows:
class Student(models.Model):
name = models.CharField()
classes = models.ManyToManyField(Class, related_name="students")
class Class(models.Model):
nombre = models.CharField
What I need is a way such that, when querying students in certain class, instead of just returnig the students enrolled in that class, it returns a QuerySet of all the students, each one with an aggregated field indicating if such student is enrolled in that class, e.g.:
[{'name':'student A', 'enrolled_in_physics':True}, {'name':'student B', 'enrolled_in_physics':False}]
I think it can be achieved through F() expressions along with ExpressionWrapper, but have no idea of how implement them; additionaly, the documentation and the examples are not very noob-friendly. Any help is appreciated, thanks!.
EDIT: Ok, I think using the word "list" is not the correct one, I need a normal QuerySet, such that let me do something like this:
student_a = query[0]
student_a.name
>>>'A'
student_a.enrolled_in_physics
>>>True
UPDATED
You could try defining a method within the student class:
class Student(models.Model):
name = models.CharField()
classes = models.ManyToManyField(Class, related_name="students")
def enrolled_in_class(self,class_name):
if len(Class.objects.filter(nombre=class_name,students__in=self)) > 0:
return True
else:
return False
students = Student.objects.all()
student_a = students[0]
student_a.name
student_a.enrolled_in_class('physics')
Original Answer:
Edit: Sorry misread question, I'll try and get an answer together for what you actually wanted: A list of all students, and binary true false if they are enrolled in a specific class.
Alright, I'm reading this as a:
I need a query that returns a list of dictionaries, indicating the student, and enrollment in a class.
#Assume: class_name = 'physics'
def get_class_list(class_name):
filtered_class = Class.object.get(nombre=class_name)
student_names = Students.objects.filter(classes__contains=filtered_class).values_list('name',flat=True)
class_list = []
for name in student_names:
class_list = {}
class_list['name'] = name
enrolled_class_string = 'enrolled_in_' + class_name
class_list[enrolled_class_string] = True
return class_list
This will give you a list of dictionaries with the keys named 'name', and 'class__name'

Django Integrated Test Passing When it Should Fail

I'm in the process of creating an assessment system using Django; however, I have an integrated test that passes and I'm not sure as to why (it should be failing). In the test, I set the grade field of the bobenrollment object to "Excellent". As you can see from the models below, the Enrollment model doesn't have a grade field (none of the models do). I was under the impression that dot notation of model objects would access the model fields (I'm probably incorrect about this). I don't want to write ineffective tests, so I would like to know what makes this test pass and what I should do to make it break. Thanks!
class ClassAndSemesterModelTest(TestCase):
def add_two_classes_to_semester_add_two_students_to_class(self):
first_semester = Semester.objects.create(text='201530')
edClass = EdClasses.objects.create(name='EG 5000')
edClass2 = EdClasses.objects.create(name='EG 6000')
first_semester.classes.add(edClass)
first_semester.classes.add(edClass2)
bob = Student.objects.create(name="Bob DaBuilder")
jane = Student.objects.create(name="Jane Doe")
bobenrollment = Enrollment.objects.create(student=bob, edclass=edClass)
janeenrollment = Enrollment.objects.create(student=jane,edclass=edClass)
bobenrollment2 = Enrollment.objects.create(student=bob,edclass=edClass2)
janeenrollment2 = Enrollment.objects.create(student=jane,edclass=edClass2)
def test_students_link_to_enrollments(self):
self.add_two_classes_to_semester_add_two_students_to_class()
edclass1 = EdClasses.objects.get(name="EG 5000")
bob = Student.objects.get(name="Bob DaBuilder")
#The three lines below are the subject of my question
bobenrollment = Enrollment.objects.get(edclass=edclass1, student=bob)
bobenrollment.grade = "Excellent"
self.assertEqual(bobenrollment.grade, "Excellent")
And the models below:
from django.db import models
class Student(models.Model):
name = models.TextField(default="")
def __str__(self):
return self.name
#TODO add models
class EdClasses(models.Model):
name = models.TextField(default='')
students = models.ManyToManyField(Student, through="Enrollment")
def __str__(self):
return self.name
class Semester(models.Model):
text = models.TextField(default='201530')
classes = models.ManyToManyField(EdClasses)
def __str__(self):
return self.text
class Enrollment(models.Model):
student = models.ForeignKey(Student)
edclass = models.ForeignKey(EdClasses)
Requirements.txt
beautifulsoup4==4.4.1
Django==1.5.4
ipython==3.1.0
LiveWires==2.0
nose==1.3.3
Pillow==2.7.0
projectname==0.1
pyperclip==1.5.11
pytz==2015.2
requests==2.10.0
selenium==2.53.6
six==1.9.0
South==1.0.2
swampy==2.1.7
virtualenv==1.11.5
I was under the impression that dot notation of model objects would access the model fields (I'm probably incorrect about this)
You're correct about this. What you're not taking into account is the fact that you can dynamically add properties to python objects. For instance:
In [1]: class MyClass():
...: pass
...:
In [2]: a = MyClass()
In [3]: a.im_a_property = 'hello'
In [4]: print a.im_a_property
hello
As you can see, the a instance will have the im_a_propery property even though it's not defined by the class. The same applies for the following line in your code:
bobenrollment.grade = "Excellent"
Django models override this behavior so you can seamlessly get DB values as properties of your model instance, but the instance is just a regular python object.
If you want to test the grade property gets saved correctly, you should modify your test to add the value of grade when creating the record and making sure the instance you assert against is the one you read from your DB (i.e. not modifying it beforehand).

How can I use multiple models to point to the same collection?

I have a single collection that can represent multiple types of data:
class Taxes(db.Document):
meta = {'collection': 'taxes'}
type = db.StringField() # State, local, federal
owner = db.ReferenceField(User, unique=True)
name = db.StringField()
fiscal_year = db.IntField()
What I am wanting to do is have either a DynamicEmbeddedDocument or make this a DynamicDocument to hold different models.
For example:
class Taxes(db.Document):
...
# This is made up syntax
data = db.EmbeddedDocumentField(StateTaxes, LocalTaxes, FederalTaxes)
Or:
class Taxes(db.DynamicDocument):
...
class StateTaxes(Taxes):
state_name = db.StringField()
class LocalTaxes(Taxes):
locality_name = db.StringField()
The goal is to do this:
# Embedded Dynamic Document example
taxes = Taxes.objects(owner=current_user).all()
state_taxes = [tax.data for tax in taxes if tax.type == 'state']
state_names = [tax_data.state_name for tax_data in state_taxes]
# Dynamic Document example
taxes = Taxes.objects(owner=current_user).all()
state_taxes = [tax for tax in taxes if tax.type == 'state']
state_names = [tax.state_name for tax in state_taxes]
Notes:
I must be able to perform 1 query to get back all types**.
Models should be separate in order to allow for clean definitions.
This example is very small, there would be a growing number of Models with very different definitions**.
All Models will have 4 or 5 fields that are the same.
The dynamic data should be relatively easy to query.
**These are the main reasons I am not using separate collections
Is this possible?
You could make a base class that covers all the base attributes (fields) and methods that you need. For example:
class BaseTaxes(db.Document):
name = db.StringField()
value = db.IntegerField()
meta = {'allow_inheritance': True}
def apply_tax(self, value):
return value*(1+self.value)
With this base class you can then create different versions:
class StateTaxes(BaseTaxes):
state = db.StringField()
As such the StateTaxes class inherits both attributes of BaseTaxes and its methods (more details here). Because it inherits the BaseTaxes class, it will be saved in the same collection (BaseTaxes) and queries can reach all subclasses:
results = BaseTaxes.objects().all()
And then, to split results by subclass:
state_taxes = [item for item in results if isinstance(item,StateTaxes)]

Creating a queryset which represents a union of querysets

Let's say I have the following models:
class House(models.Model):
address = models.CharField(max_length=255)
class Person(models.Model):
name = models.CharField(max_length=50)
home = models.ForeignKey(House, null=True, related_name='tenants')
class Car(models.Model):
make = models.CharField(max_length=50)
owner = models.ForeignKey(Person)
Let's say I have a need (strange one, albeit) to get:
list of people who live in a house or are named 'John'
list of cars of the above people
I would like to have two functions:
get_tenants_or_johns(house)
get_cars_of_tenants_or_johns(house)
I could define them as:
from django.db.models.query_utils import Q
def get_cars_of_tenants_or_johns(house):
is_john = Q(owner__in=Person.objects.filter(name='John'))
is_tenant = Q(owner__in=house.tenants.all())
return Car.filter(is_john | is_tenant)
def get_tenants_or_johns(house):
johns = Person.objects.filter(name='John')
tenants = house.tenants.all()
return set(johns) | set(tenants)
The problem is that the logic is repeated in the above examples. If I could get get_tenants_or_johns(house) to return a queryset I could define get_cars_of_tenants_or_johns(house) as:
def get_cars_of_tenants_or_johns(house):
return Car.objects.filter(owner__in=get_tenants_or_johns(house))
In order to do that, get_tenants_or_johns(house) would need to return a union of querysets, without turning them into other collections.
I cannot figure out how to implement get_tenants_or_johns(house) so that it would return a queryset containing a SQL UNION. Is there a way to do that? If not, is there an alternate way to achieve what I am trying to do?
The | operator on two querysets will return a new queryset representing a union.
The function will need to change to (got rid of set() wrappers):
def get_tenants_or_johns(house):
johns = Person.objects.filter(name='John')
tenants = house.tenants.all()
return johns | tenants
and everything will work exactly like needed.
You mention users who live in a house, but have no mention of your User model.
I think you really need to take a long look at the structure of your application - there are probably much easier ways to accomplish your goal.
But to answer your question let's set up three helper functions. Since, as I mentioned above, you haven't outlined what you want to do with the User class - I've assumed that the house that will be passed to these functions is an address:
helpers.py
def get_johns(house):
is_john = Person.objects.filter(name='John')
return is_john
def get_cars_of_tenants(house):
cars = Car.objects.filter(owner__home__address=house)
return cars
def get_tenants(house):
tenants = Person.objects.filter(home__address=house)
return tenants
Now you could create a view for each of your combination queries:
views.py:
import helpers.py
from itertools import chain
def get_cars_of_tenants_or_johns(request, house):
results = list(chain(get_cars_of_tenants(house), get_johns(house)))
return render_to_response('cars_or_johns.html', {"results": results,})
def get_tenants_or_johns(request, house):
results = list(chain(get_tenants(house), get_johns(house)))
return render_to_response('tenants_or_johns.html', {"results": results,})
And this can go on for all of the various combinations. What is returned is results which is a list of all of the matches that you can iterate over.

Categories

Resources