Giter Site home page Giter Site logo

togg1 / graphene-django-cud Goto Github PK

View Code? Open in Web Editor NEW
77.0 7.0 35.0 449 KB

Easy and painless CUD-mutations for graphene-django.

License: MIT License

Makefile 0.19% Python 99.81%
graphene-django graphene graphene-django-cud graphql django-graphql django

graphene-django-cud's Introduction

Graphene Django CUD

Version Build status Documentation Status License

This package contains a number of helper mutations making it easy to construct create, update and delete mutations for django models.

The helper mutations are:

  • DjangoCreateMutation
  • DjangoPatchMutation
  • DjangoUpdateMutation
  • DjangoDeleteMutation
  • DjangoBatchCreateMutation
  • DjangoBatchPatchMutation
  • DjangoBatchUpdateMutation
  • DjangoBatchDeleteMutation
  • DjangoFilterUpdateMutation
  • DjangoFilterDeleteMutation

The package handles both regular ids and relay ids automatically.

Installation

pip install graphene_django_cud

Basic usage

To use, here illustrated by DjangoCreateMutation, simply create a new inherting class. Suppose we have the following model and Node.

class User(models.Model):
    name = models.CharField(max_length=255)
    address = models.TextField()

class UserNode(DjangoObjectType):
    class Meta:
        model = User
        interfaces = (Node,)

Then we can create a create mutation with the following schema

class CreateUserMutation(DjangoCreateMutation):
    class Meta:
        model = User


class Mutation(graphene.ObjectType):
    create_user = CreateUserMutation.Field()


class Query(graphene.ObjectType):
    user = graphene.Field(UserNode, id=graphene.String())

    def resolve_user(self, info, id):
        return User.objects.get(pk=id)


schema = Schema(query=Query, mutation=Mutation)

Note that the UserNode has to be registered as a field before the mutation is instantiated. This will be configurable in the future.

The input to the mutation is a single variable input which is automatically created with the models fields. An example mutation would then be

mutation {
    createUser(input: {name: "John Doe", address: "Downing Street 10"}){
        user{
            id
            name
            address
        }
    }
}

Documentation

The full documentation can be found at https://graphene-django-cud.readthedocs.io/en/latest/.

graphene-django-cud's People

Contributors

bigtimecriminal avatar bjmc avatar calummackervoy avatar dependabot[bot] avatar e3oroush avatar janosroden avatar keithhackbarth avatar m69k65y avatar markddavidoff avatar martasd avatar mbuvarp avatar plebbimon avatar rymanso avatar sjdemartini avatar togg1 avatar wito-alex avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphene-django-cud's Issues

before_save not being executed

class CreateTableMutation(mutations.DjangoCreateMutation):
    class Meta:
        model = Table
        exclude_fields = ('owner',)
    create_column = CreateTableColumnMutation.Field()

    @classmethod
    def before_save(cls, root, info, input, obj: Table):
        obj.owner = User.objects.get(pk=1)
        return obj

I've the following code, before_save doesn't get executed (I copied the example in docs)

this is what I get:

{
  "errors": [
    {
      "message": "NOT NULL constraint failed: query_builder_table.owner_id",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "createTable"
      ]
    }
  ],
  "data": {
    "createTable": null
  }
}

It's supposed to provide the owner object through the before_save, right?

How to including custom field in DjangoPatchMutation?

I have a use-case where I need your inputs on how to handle it. Any help is highly appreciated.

Lets say I have these models -

class Dashboard(models.Model):
    name = models.CharField(max_length=255) 

class Widget(models.Model):
    name = models.CharField(max_length=255)
    layout = models.CharField(max_length=255)
    widget = models.ForeignKey(Dashboard) 
class DashboardUpdateMutation(DjangoPatchMutation):
    class Meta:
        model = Dashboard
        login_required = True

class DashboardMutation(graphene.ObjectType):
    update_dashboard = DashboardUpdateMutation.Field()

I need to update the Dashboard fields and its widgets through some custom logic. I want to write the patch mutation as follows.

`mutation{
  updateDashboard(id: "RGFzaGJvYXJkTm9kZTox", input: {
    name: "Main Dashboard",
    mycustomfield: "layout json",
  }) {
    dashboard {                
        id,
        name,
   }
}
}`

How should I add mycustomfield above, so that I can run the logic in its resolver? A code example would help a lot.

Upload file with django-upload results in serialization error

I am getting an error when using a custom field type to upload a file with the graphene-file-upload library.

This is the model

class Candidate(models.Model):
    first_name = models.CharField(max_length=256)
    last_name = models.CharField(max_length=256)
    resume = models.FileField()

This code incorporate graphene-django-cud Create Mutation with the Upload class from graphene-file-upload

class CreateCandidateMutation(DjangoCreateMutation):
    class Meta:
        model = Candidate
        field_types = {
            "resume": Upload(required=True)
        }

    @classmethod
    def handle_resume(cls, value, *args, **kwargs):
        return value[0]

The server then response with this error: Object of type InMemoryUploadedFile is not JSON serializable

This code works when I write my own mutation without this library:

class CandidateCreateInput(graphene.InputObjectType):
    first_name = graphene.String(required=False)
    last_name = graphene.String(required=False)
    resume = Upload(required=False)

class CandidateCreateMutation(graphene.Mutation):
    class Arguments:
        input = CandidateCreateInput(required=True)
        
        candidate = graphene.Field(CandidateNode)

    def mutate(self, info, input=None):
        candidate = Candidate.objects.create(
            resume = input.resume[0]
        )
        return CandidateCreateMutation(candidate=candidate)

When I look in the GraphiQL docs, the resume field shows as an Upload scalar type when I use the django-graphene-cud mutation, but shows as a String type with my vanilla graphene mutation.

Make relay ids configurable

Currently, graphene-django-cud is very persistent on returning relay IDs. We'd probably want this to be configurable, as other parts of the library are agnostic in this respect.

Feature request: (batch) delete by IDs

I think it would be very valuable to being able to delete several model instances via one GraphQL mutation call by IDs (or potential other unique fields).

One possible design could combine the fields of DjangoDeleteMutation and DjangoBatchDeleteMutation to something like this in case all IDs have been found

mutation {
  deleteModels(id: [1, 2, 3]) {
    deletionCount
    deletedIds
    missedIds
  }
}

{
  "data": {
    "deleteModels": {
      "deletionCount": 3,
      "deletedIds": [1, 2, 3],
      "missedIds": null,
    }
  }
}

and this in case some Id(s) have not been found

mutation {
  deleteModels(id: [1, 2, 3, 4, 5]) {
    deletionCount
    deletedIds
    missedIds
  }
}

{
  "data": {
    "deleteModels": {
      "deletionCount": 3,
      "deletedIds": [1, 2, 3],
      "missedIds": [4, 5],
    }
  }
}

What do you think?

Error updating nested field using many_to_one_extras when there are restrictions on related model

Above all, many congratulations for such a good job.
Suppose there are two models, a model A and a model B that has a foreign key to model A with and related name = "ab," and also two fields "name" and "value".

So to update a model A and setting as many models B as necessary I specify in UpdateAMutation:
many_to_one_extras = {
"ab": {
"exact": {"type": "auto"}
},

In model B I have the unique type constraint (unique_together = ('name', 'a_id'))

The problem is that when I try to update A and its relations in B in the same mutation, if there is some value in B that already existed with equal ('name', 'a_id'), the constraint throws error.

Please is there a way to do it?

Add auto_context_queryset_filter Meta field

Would be nice having a field to restrict the available queryset for update and patch mutations based on context values. For example, say you have the field organization in the context. You could do something like this:

class PatchUserMutation(DjangoPatchMutation):
  class Meta:
    model = User
    auto_context_queryset_filter = {
      "organization": "organization"
    }

A user would then only be able to patch users in the same organization as them.

Many to Many extras with through model

I have these models:

class Employee(models.Model):
    name = models.CharField(max_length=30)
    offices = models.ManyToManyField(
        "Office",
        through="Assignment",
        blank=True,
    )

class Office(models.Model):
    name = models.CharField(max_length=30)

class Assignment(models.Model):
    
    office = models.ForeignKey(
        "Office",
        on_delete = models.CASCADE,
    )
    employee = models.ForeignKey(
        "Employee",
        on_delete = models.CASCADE, 
    )
    primary = models.BooleanField()

How would I go about creating a record in the Assignment model automatically with CreateEmployeeMutation.

My CreateEmployeeMutation looks like this:

class CreateEmployeeMutation(DjangoCreateMutation):  # Create
    class Meta:
        model = Employee
        many_to_many_extras = {
            "offices": {
                "add": {
                    "type": "CreateAssignmentInput",
                }
            }
        }

The problem is that CreateAssignmentInput requires the ID of the employee which currently being created. If I change "CreateAssignmentInput" to "auto" then it asks for the fields from the Office model as if it's going to add a new office instead of a new Assignment.

Thanks for your great work!

Many to many field is not reset when using "exact"

I have found another somewhat related issue for the following model and mutation:

class Beo(BaseModel):
    ... 
    organizers = ManyToManyField(
        UserProfile, related_name="organized_beos", blank=True,
        through="BeoOrganizer", through_fields=("beo", "organizer")
    )

class BeoOrganizer(BaseModel):
    beo = ForeignKey(Beo, on_delete=CASCADE)
    organizer = ForeignKey(UserProfile, related_name="organized_beo", on_delete=CASCADE)

class UpdateBeo(DjangoPatchMutation):
    class Meta:
        model = Beo
        many_to_many_extras = = {
               "organizers": {"exact": {"type": "ID"}},
}

When using exact in DjangoPatchMutation, I would expect that the following mutation would clear the organizers list. In reality, nothing changes:

image

Custom PK incompatibility

Hello there!
I've been trying to use graphene-django-cud with models where 'id' is not the name of the pk and it crashes. I don't see a way to set that value and 'id__in' seems to be 'hardcoded' in several places. Is there a way of setting custom pks I'm missing?

many to many extra not working

Hi I have these models

class package(models.Model):
    items = models.ManyToManyField('product.item', verbose_name=_("Items"), related_name="package_items")

class item(models.Model):
    products = models.ManyToManyField('product.product', verbose_name=_("Products"), null=True, blank=True)

class product(models.Model):
    options = models.ManyToManyField("product.option", verbose_name=_("Product options"), null=True, blank=True)

and this is my mutation for package and item

class create_package(DjangoCreateMutation):
    class Meta:
        model = package
        many_to_many_extras = {
            'items': {
                'add':{'type': 'CreateitemInput'}
            }
        }

class create_item(DjangoCreateMutation):
    class Meta:
        model = item
        many_to_many_extras = {
            'products': {
                'add':{'type': 'CreateproductInput'}
            }
        }

class create_product(DjangoCreateMutation):
    class Meta:
        model = product
        many_to_many_extras = {
            'options': {
                'add':{'type': 'CreateoptionInput'}
            }
        }

And when I run a mutation like this:

mutation{
  createPackage(
    input:{
      name:"random"
      description:"boring"
      sideBarText:"sample"
      items:[
        1
      ]
      itemsAdd:[
        {
          name:"bla bla bla"
          displayName:"kdjhb"
          products:[
            "cHJvZHVjdF90eXBlOjE="
          ]
          productsAdd:[
            {
              name:"product bla"
              description:"double trouble"
              price:"99.99"
            }
          ]
        }
      ]
    }
  ){
    package{
      name
      items{
        edges{
          node{
            name
            products{
              edges{
                node{
                  name
                  price
                }
              }
            }
          }
        }
      }
    }
  }
}

I only get the added product returned, why isn't the other product being added?

Is there a way to extends a mutation with custom_fields?

Is there a way to extend a mutation with "custom_fields"? We have dynamic custom fields per module, and we don't want to re-code everything on each module that have custom fields. I would like to have a class that I can extends and this class will manage everything. You can find below the code, and the error I'm getting is : Variable "$input" got invalid value In field "customFields": Unknown field. I'm new to python/django/graphene, any help is appreciated! Thanks

Supplier Model

class Supp(base.SoftDeleteMixin, base.TimestampMixin, base.UseCustomField, base.BaseTenantModel):
    class Meta:
        db_table = 'supp'
        verbose_name = 'Supplier'

UseCustomField code

class UseCustomField(TenantModel):
    class Meta:
        abstract = True
        app_label = 'api'
        managed = False

    field_data_row = models.OneToOneField(
        'FieldDataRow',
        verbose_name='Custom Field',
        on_delete=models.RESTRICT,
        null=True, blank=True
    )

Supplier Type

class SuppCreateMutation(base.CreateCustomFieldMutation, base.BaseCreateMutation):
    class Meta:
        login_required = True
        model = Supp
        one_to_one_extras = {"location": {"type": "auto"}}

Extended Mutation

class CustomField(graphene.InputObjectType):
    field = graphene.ID()
    value = graphene.String()

class CreateCustomFieldMutation():
    class Meta:
        abstract = True
        custom_fields = {
            "customFields": graphene.List(CustomField)
        }

    @classmethod
    def before_save(cls, root, info, input, obj: Supp):
        if input.get("customFields"):
            field_data_row = FieldDataRow.objects.create()
            obj.field_data_row = field_data_row

            for field in input.get("customFields"):

                FieldDataValue.objects.create(field_data_row=field_data_row, field=Field(pk=field.field), value=field.value)

        return obj

Upsert classes

There is likely a use case for having a DjangoUpsertMutation.

Autogenerated graphene INPUT fields interpret Decimal fields as Float fields

Bug: The ObjectTypeInput, auto generated by a create/update/patch mutation interprets Django Decimal fields as Float fields. Graphene has added support for Decimal fields.

I am required to write my mutation this way:

mutation updateMultipleFieldsProjectl($projectId: ID!, $name: String, $degradation:
        Float = 10.00) {
            updateProject(id: $projectId, input: {name: $name , degradation: $degradation})

However, in my model, degradation is a django DecimalField.
Currently I am required to hook into before_save and convert the Float to a Decimal, and define it as a Float in my graphql query.

many_to_many_extras not working for ArrayReferenceField (djongo)

Model:
class Scholarship(models.Model):
name = models.CharField(max_length=30)

class Student(models.Model):
name = models.CharField(max_length=30)
rollno = models.CharField(max_length=30)
scholarships = models.ArrayReferenceField(Scholarship, on_delete=models.CASCADE)

Alias `only_fields` as `fields` and `exclude_fields` as `exclude`

TL;DR, Graphene-Django is renaming them, and I assume graphene-django-cud wants to match it: graphql-python/graphene-django#691

To match Django REST Framework's ModelSerializer, Graphene-Django is switching the names of only_fields and exclude_fields to fields and exclude respectively. They've added the new names as aliases already, and are now raising DeprecationWarnings when using the old names, as they plan to remove the old names in v3. I expect that graphene-django-cud want to follow their lead on this?

Bulk Update and Patch mutations are not exposed

Maybe I'm importing incorrectly but this doesn't work for me:
from graphene_django_cud.mutations import DjangoBatchPatchMutation

It seems that the mutatation/__init__.py file doesn't have the new Batch/Filter Mutations in __all__.

login_required not working

Hello,

Currently login_required is ignored in all mutations, I think the problematic line is _meta.login_required = _meta.login_required or ( instead of _meta.login_required = login_required or (.

Take a look please, thanks!

Validation error on unique_together fields outputs empty message.

class Dashboard(models.Model):
    name = models.CharField(max_length=255)
    owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='dashboards')

    class Meta:
        ordering = ['-id']
        unique_together = ['name', 'owner']

The validation error gets hit properly, but the message field is empty for this error.
{"errors":[{"message":"","locations":[{"line":2,"column":21}],"path":["createDashboard"]}],"data":{"createDashboard":null}}

one_to_one_extras deep nesting problem

Hello,
I would like to thank you a lot for creating such a nice library to deal with graphql

I faced an issue with deep nesting when dealing with one to one relation, here is an example :

class Marchendise(models.Model):
    type = models.CharField(max_length=100)

class Prevision(models.Model):
    marchandise = models.OneToOneField( 'livraison.Marchendise', on_delete=models.CASCADE)
class Rotation(models.Model):
    prevision = models.OneToOneField('livraison.Prevision', on_delete=models.CASCADE)
class CreateMarchandiseMutation(DjangoCreateMutation):
    class Meta:
        model = models.Marchandise

class CreatePrevisionMutation(DjangoCreateMutation):
    class Meta:
        model = models.Prevision
        type_name = "CreatePrevisionType"
        one_to_one_extras = {
            "marchandise": {"type": "auto"}
        }

class RotationWithPrevisionMutation(DjangoCreateMutation):
    class Meta:
        model = models.Rotation
        type_name = "CreateRotationTypeWithPrevision"
        one_to_one_extras = {
            'prevision': {
                "type": "auto"
            }
        }

when I create a new rotation the query will look like that:

mutation{
  create_rotation_with_prevision(input:{
    prevision:{
      marchendise:"1"
    # marchendise:{ type:"container" }    ------ What i want to achieve
    }
  }){
    rotation{
      id
    }
  }

The problem is that the type of merchandise is ID instead of nested
thank you in advance

required_fields not working for DjangoPatchMutation

The required_fields meta option does not work for DjangoPatchMutation. While I get that generally in patch mutations all fields should be optional, I still think fields should be required if explicitly set as such.

Is "id" required for update?

the examples in the guide do:

mutation {
    patchUser(input: {name: "John Doe"}){
        user{
            id
            name
            address
        }
    }
}

but when i do a similar query in my code, with only an input passed i get:
argument \"id\" of type \"ID!\" is required but not provided.

Choices Field created via models.TextChoices(or its analogues) class

python version 3.10.3
django version 4.0.3
graphene-django from main branch latest commit by date of posting(f6ec0689c18929344c79ae363d2e3d5628fa4a2d)
graphene_django_cud version 0.10.0

I was trying to create a DjangoCreateMutation(actually it fails for any kind of mutation) with this model

from django.db import models
from django.contrib.auth import get_user_model


User = get_user_model()


class Staff(models.Model):
    class StaffStatus(models.TextChoices):
        WORKING = 'working', 'Working'
        SUSPENDED = 'suspended', 'Suspended'
        FIRED = 'fired', 'Fired'

    first_name = models.CharField(max_length=64)
    middle_name = models.CharField(max_length=64)
    last_name = models.CharField(max_length=64)
    phone = models.CharField(max_length=32)
    email = models.CharField(max_length=256)
    position = models.CharField(max_length=64)
    address = models.CharField(max_length=512)
    status = models.CharField(max_length=16, choices=StaffStatus.choices, default=StaffStatus.WORKING)
    is_admin = models.BooleanField(default=False)

    user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True, related_name='staff')

    def __str__(self):
        return f'{self.last_name} {self.first_name}({self.id})'

I suppose most of the fields can be skipped except the one with choices which was created via class _(models.TextChoices) or its analogues in it.

And when I tried to run app it fails with message

File "lib\site-packages\graphene_django_cud\converter.py", line 116, in convert_django_field_with_choices     
    from_registry.kwargs['description'] = field.help_text
AttributeError: 'BlankValueField' object has no attribute 'kwargs'. Did you mean: 'args'?

Excluding nested fields in create mutation

Hi,

I want to exclude a few fields on my related OneToOne model. I have the following code for my create mutation. The nested field created and modifed are still available for the creation. Any clues to point me in the right direction is highly appreciated.

class CreateStackMutation(MutationMixin, DjangoCreateMutation):
    """Create dynamic settings"""
    class Meta:
        model = Stack
        exclude_fields = ('modified', 'created', 'email__modified', 'email__created')
        one_to_one_extras = {"email": {"type": "auto"}}

'OneToOneRel' object has no attribute 'help_text'

hi

I have the following model and mutation:

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    contact = models.CharField(max_length=20, null=True, blank=True)
    avatar = models.ImageField(upload_to='user/%Y/%m/%d/', default="user.svg")
    bio = HTMLField('description', blank=True, null=True, default='Decrivez-vous')

    @receiver(post_save, sender=User)
    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            Profile.objects.create(user=instance)

    @receiver(post_save, sender=User)
    def save_user_profile(sender, instance, created, **kwargs):
        instance.profile.save()
class CreateUserMutation(DjangoCreateMutation):
    class Meta:
        model = User

I got the error when I try to runserver

File "C:\ProgramData\Anaconda3\lib\site-packages\graphene_django_cud\converter.py", line 256, in convert_onetoone_field_to_djangomodel
    return List(ID, description=field.help_text, required=is_required(field, required))
AttributeError: 'OneToOneRel' object has no attribute 'help_text'

Problem in the disambiguate_id function

Hi,
I have a model with a foreign key named kpi which allude to another model with a PK named key (with type string). The problem is that whenever I try to insert into the first model with a create mutation and kpi="somekey", I get an error regarding that kpi_id=-1 does not exist.

I figured out that it is because of what the disambiguate_id does to the provided id:

def disambiguate_id(ambiguous_id: Union[int, float, str]):
    """
    disambiguate_id takes an id which may either be an integer-parsable
    variable, either as a string or a number; or it might be a base64 encoded
    global relay value.

    The method then attempts to extract from this token the actual id.

    :return:
    """
    # First see if it is an integer, if so
    # it is definitely not a relay global id
    final_id = -1
    try:
        final_id = int(ambiguous_id)
        return final_id
    except ValueError:
        # Try global value
        (_, final_id) = from_global_id(ambiguous_id)
    finally:
        return final_id

this function assumes that if a provided id is not integer-parsable, it is a relay id. However, at least in my case, this is not true. In this case, this function returns -1 which is wrong (I expect it to return my original id, i.e. somekey).

The problem also exist in the disambiguate_ids function.

Help required

When I tried to create a mutation using DjangoCreateMutation

I am getting
NameError: name 'DjangoCreateMutation' is not defined

Plz help me how to resolve this

Primary key handling needs to be hardened

In light of #28, we need to improve primary key handling, as the type should be "ID" by default. However, we need to severely harden how primary keys are handled throughout the system, as some primary keys may be non-integer, non-auto-incremented fields, which will break.

Also, #28 would break setups where you'd want a non-required primary key field.

  • Harden how primary keys are used throughout the codebase, make way more generic.
  • Make primary key handling overrideable on every mutation
  • Fix the specific case in #28

Incorrectly generated mutation field input type

I have a model called Beo with a many-to-many field called labels like this:

class Beo(BaseModel):
    ...
    labels = ManyToManyField(BeoLabel, blank=True)

I also have a create mutation for labels with the default input type:

image

In the create mutation, I would like to specify that it is possible to create labels directly while creating the Beo instance:

class CreateBeo(DjangoCreateMutation):
    class Meta:
        model = Beo
        many_to_many_extras = {
           "labels": {"exact": {"type": "CreateBeoLabelInput"}},

In the resulting mutation, however, I only see the [ID] as the input type for labels while expecting something like [CreateBeoLabelInput]:

Screen Shot 2019-09-18 at 16 23 16

History does not get tracked for many to many field

Hi Tormod,

I have the following model and mutation defined:

class Beo(BaseModel):
    ... (some simple fields are here)
    organizers = ManyToManyField(
        UserProfile, related_name="organized_beos", blank=True,
        through="BeoOrganizer", through_fields=("beo", "organizer")
    )
    history = HistoricalRecords(user_model=UserProfile)

class BeoOrganizer(BaseModel):
    beo = ForeignKey(Beo, on_delete=CASCADE)
    organizer = ForeignKey(UserProfile, related_name="organized_beo", on_delete=CASCADE)
    history = HistoricalRecords(user_model=UserProfile)

class CreateBeo(DjangoCreateMutation):
    class Meta:
        model = Beo
        many_to_many_extras = = {
               "organizers": {"exact": {"type": "ID"}},
}

Beo is a model which uses django-simple-history, a library to keep track of object changes. According to the docs:

"django-simple-history functions by saving history using a post_save signal every time that an object with history is saved."

When I execute the CreateBeo mutation, the history gets properly recorded for simple fields of the new beo object as expected. However, it does not get recorded for the many-to-many organizers field even though there is a new entry in the BeoOrganizers table. I assume this is related to history using the post_save signal. Is that right? Is this something that could be enabled or is that an inherent limitation?

Many thanks!

Improve documentation

  • Add documentation for the available hooks.
  • Add better documentation for import paths.
  • Add documentation for one to one extras.

Redundant type created for choice charfield

When creating a simple model with a choice charfield:

# Model

BAR_CHOICES = [
    ('OPTION1', 'Option 1'),
    ('OPTION2', 'Option 2'),
    ('OPTION3', 'Option 3')
]


class Foo(models.Model):
    bar = models.CharField(max_length=32, choices=BAR_CHOICES, null=True, blank=True)

# Type

from graphene_django import DjangoObjectType as DOT

class FooType(DOT):
    class Meta:
        model = Foo
        filter_fields: Dict[str, str] = {}

# Mutation

class CreateFoo(DjangoCreateMutation):
    class Meta:
        model = Foo

This results in two identical enum types being generated with different names, FooBar and FooBarInput. Is this intended behavior, or a valid issue?

Fix pytest warnings

When I run tests in django projects with pytest and pytest-django I get some warnings from which at least one is caused by graphene-django-cud.

.../graphene_django_cud/converter.py:57: RemovedInDjango40Warning: force_text() is deprecated in favor of force_str().
    name = to_const(force_text(name))

-- Docs: https://docs.pytest.org/en/latest/warnings.html
============================ SnapshotTest summary ============================

It's not critical cause it's about warnings but a bit annoying cause potential own warnings are kind of hidden. Depending on which django versions you want to support there needs to be taken some care w.r.t. backward compatibility when fixing the warnings.

Cannot set a default for enumeration

I have the following field in my Beo model:

class Beo(BaseModel):
    ...
    STATUSES = (("UNLOCKED", "Unlocked"), ("LOCKED", "Locked"), ("SIGNED", "Signed"))
    status = CharField(max_length=16, choices=STATUSES, default="UNLOCKED")

When using DjangoCreateMutation, I get an enumeration for this field as expected:

image

When I call the mutation without including the status field, I get the following error message even though I specify a default in the Beo model:

In field \"status\": Expected \"BeoStatus!\", found null.",

Create and update mutations referencing not-yet-created entries

One thing that would be nice to have is the possibility to create complex mutations with relations referring to objects that have not yet been created. For instance:

mutation{
    createSomething(input: {
        _id: "ID1", 
        field: "Value",
        someRelation: [{
           anotherField: "value", 
           someNonObviousRelationField: "ID1"
        }] 
   }){
      ...
   }

Clearly, this issue must include a fair bunch of complex logic to ensure all IDs are resolved before usage.

Choices field not marked optional in DjangoPatchMutation

I have the following model and mutation:

class Report(BaseModel):
    workspace = ForeignKey(Workspace, on_delete=CASCADE)
    name = CharField(max_length=255)

    MODULES = (("EVENT", "Event"), ("TASK", "Task"), ("AGENDA", "Agenda"), ("BEO", "Beo"))
    module = CharField(max_length=32, choices=MODULES)
    author = ForeignKey(UserProfile, on_delete=CASCADE)
    config = JSONField()
class UpdateReport(DjangoPatchMutation):
    class Meta:
        model = Report
        type_name = "UpdateReportInput"


module is NOT optional even though every field should be optional by default in DjangoPatchMutation according to the documentation:

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.