1

I have an event model with a foreign keys to location and photographer models.

# event model
...
class Event(models.Model):
    STATUS = (
        ("Scheduled", "Scheduled"),
        ("Cancelled", "Cancelled"),
        ("Available", "Available"),
        ("Complete", "Complete"),
    )
    location = models.ForeignKey(
        Location, on_delete=models.SET_NULL, null=True, related_name="event_location"
    )
    photographer = models.ForeignKey(
        Photographer,
        on_delete=models.SET_NULL,
        null=True,
        related_name="event_photographer",
    )
    event_date = models.DateField()
    status = models.CharField(max_length=50, choices=STATUS, default="Scheduled")
    created = models.DateTimeField(auto_now_add=True)

The photographer model has first_name, last_name and email as properties. I would like to be able to filter events by supplying the photographer's details, for example their email. In my REST api, I made it such that I could pass the any django filter query in url like this: /events/?photogrpher__email=name@example.com. I am trying to replicate the same behavior in graphql using graphene.

# types.py
...
class EventType(DjangoObjectType):
    class Meta:
        model = Event
        interfaces = (relay.Node,)
        filterset_class = EventFilter


class LocationType(DjangoObjectType):
    class Meta:
        model = Location
        filterset_class = LocationFilter
        interfaces = (relay.Node,)

class PhotographerType(DjangoObjectType):
    class Meta:
        model = Photographer
        filterset_class = PhotographerFilter
        interfaces = (relay.Node,)

Filters:

# filters.py
...
class PhotographerFilter(FilterSet):
    class Meta:
        model = Photographer
        fields = "__all__"

        exclude = [
            "password",
            "profile_picture",
        ]


class EventFilter(FilterSet):

    class Meta:
        model = Event
        fields = "__all__"
        filter_fields = {
            "event_photographer": ["exact", "first_name", "last_name", "email"],
            "event_location": ["exact", "name"],
        }

class LocationFilter(FilterSet):
    class Meta:
        model = Location
        fields = "__all__"

Query:

# queries.py
...
class Query(ObjectType):
    all_photographers = DjangoFilterConnectionField(PhotographerType)
    photogrpaher = relay.Node.Field(PhotographerType)
    event = relay.Node.Field(EventType)
    all_events = DjangoFilterConnectionField(EventType)
    location = relay.Node.Field(LocationType)
    all_location = AdvancedDjangoFilterConnectionField(LocationType)

The resulting api doesn't have the related fields as arguments, just the model fields. I tried adding event_photographer field manually:

# filters.py
...
class EventFilter(FilterSet):
    event_photographer = django_filters.CharFilter(field_name="event_photographer")
...

With this addition, when I pass any string to I get the parameter eventPhotographer, but not the sub parameters like firstName, email etc. A sample query like this:

    allEvents(eventPhotographer:"name@example.com"){
        edges {
            node {
                id
                photographer {
                    firstName
                }
           }
        }
    }

Gives this error:

"message": "Cannot resolve keyword 'event_photographer' into field. Choices are: blocked_slot_event, booked_day_event, booked_slot_event, calendar_event, created, event_date, event_shoot, id, location, location_id, photographer, photographer_id, product_sale_event, set_photos, status",

The extra fields are related names for other models that have a foreign key to Events

What am I doing wrong and what is the correct and easiest way to achieve this.

keystroke33
  • 159
  • 3
  • 11

1 Answers1

0

You definitely can do something like that (see double underscore between model and column):

# filters.py
class PhotographerFilter(FilterSet):
    class Meta:
        model = Photographer
        fields = "__all__"


class EventFilter(FilterSet):
    photographer__name = CharFilter()
    
    class Meta:
        model = Event
        fields = "__all__"

This query would work and filter by photographer name:

query {
    allEvents(photographer_Name: "maro") {
        edges {
            node {
                photographer {
                    name
                }
            }
        }
    }
}

You can add corresponding filters for firstName, email, etc.

jorzel
  • 1,216
  • 1
  • 8
  • 12
  • 1
    I started doing this, but realized I would have to do this fore every model and every field I want to filter for. I have very many models and some of theme have quite a large number of fields and more will be created soon. [I started an issue](https://github.com/graphql-python/graphene-django/issues/1314) on github with a question I had here previously if you want to maybe look at it. – keystroke33 Apr 01 '22 at 15:12