Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable in place update of fields #22

Merged
merged 1 commit into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,21 @@ How the value of a field is retrieved from a model instance:
1. The collection field name is called as a property of the model instance
2. If `value` is provided, it will be called as a property or method of the model instance

Where the collections live is totally dependent on you but we recommend having a `collections.py` file in the django app where the model you are creating a collection for is.
Where the collections live is totally dependent on you but we recommend having a `collections.py` file
in the django app where the model you are creating a collection for is.

> [!NOTE]
> We recommend displaying data from ForeignKey or OneToOne fields as string attributes using the display decorator to avoid triggering database queries that will negatively affect performance.
> We recommend displaying data from ForeignKey or OneToOne fields as string attributes using the display decorator to
> avoid triggering database queries that will negatively affect performance
> [Issue #16](https://github.com/Siege-Software/django-typesense/issues/16).

### Update Collection Schema [WIP]
To add or remove fields to a collection's schema in place, update your collection then run:
`SongCollection.update_typesense_collection()`

### Admin Integration
To make a model admin display and search from the model's Typesense collection, the admin class should inherit `TypesenseSearchAdminMixin`
To make a model admin display and search from the model's Typesense collection, the admin class should
inherit `TypesenseSearchAdminMixin`

```
from django_typesense.admin import TypesenseSearchAdminMixin
Expand Down
12 changes: 2 additions & 10 deletions django_typesense/admin.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import logging

from django.contrib import admin, messages
from django.contrib.admin import helpers
from django.contrib.admin.options import IncorrectLookupParameters
from django.contrib.admin.utils import model_ngettext
from django.contrib import admin
from django.contrib.auth.admin import csrf_protect_m
from django.core.exceptions import PermissionDenied
from django.db import transaction, router
from django.db.models import QuerySet
from django.forms import forms
from django.http import JsonResponse, HttpResponseRedirect
from django.template.response import TemplateResponse, SimpleTemplateResponse
from django.utils.translation import gettext as _
from django.utils.translation import ngettext
from django.http import JsonResponse

from django_typesense.utils import typesense_search
from django_typesense.paginator import TypesenseSearchPaginator
Expand Down
4 changes: 0 additions & 4 deletions django_typesense/changelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

from django import forms
from django.contrib import messages
from django.contrib.admin import (
BooleanFieldListFilter, AllValuesFieldListFilter, ChoicesFieldListFilter, RelatedFieldListFilter
)
from django.contrib.admin.exceptions import DisallowedModelAdminToField
from django.contrib.admin.options import (
IS_POPUP_VAR,
Expand All @@ -13,7 +10,6 @@
)
from django.contrib.admin.views.main import ChangeList
from django.core.paginator import InvalidPage
from django.db import models
from django.db.models import OrderBy
from django.utils.translation import gettext
from django.utils.dateparse import parse_datetime
Expand Down
41 changes: 39 additions & 2 deletions django_typesense/collections.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from collections import defaultdict

import django

from typing import Optional, Iterable, Union, Dict
Expand Down Expand Up @@ -141,7 +143,7 @@ def schema_fields(self) -> list:
def _get_object_data(self, obj):
return {field.name: field.value(obj) for field in self.fields.values()}

@cached_property
@property
def schema(self) -> dict:
"""
Returns:
Expand All @@ -157,20 +159,55 @@ def schema(self) -> dict:

def create_typesense_collection(self):
"""
Create a new typesense collection on the typesense server
Create a new typesense collection (schema) on the typesense server
"""
try:
client.collections.create(self.schema)
except ObjectAlreadyExists:
pass

def update_typesense_collection(self):
"""
Update the schema of an existing collection
"""
current_schema = self.retrieve_typesense_collection()
schema_changes = {}
field_changes = []

# Update fields
existing_fields = {field['name']: field for field in current_schema['fields']}
schema_fields = {field['name']: field for field in self.schema_fields}
# The collection retrieved from typesense does not include the id field so we remove the one we added
schema_fields.pop('id')

dropped_fields_names = set(existing_fields.keys()).difference(schema_fields.keys())
field_changes.extend([{'name': field_name, 'drop': True} for field_name in dropped_fields_names])

for field in schema_fields.values():
if field['name'] not in existing_fields.keys():
field_changes.append(field)
else:
if field != existing_fields[field['name']]:
field_changes.append(field)

if field_changes:
schema_changes['fields'] = field_changes

if not schema_changes:
return

return client.collections[self.schema_name].update(schema_changes)

def drop_typesense_collection(self):
"""
Drops a typesense collection from the typesense server
"""
client.collections[self.schema_name].delete()

def retrieve_typesense_collection(self):
"""
Retrieve the details of a collection
"""
return client.collections[self.schema_name].retrieve()

def delete(self):
Expand Down
Loading