Coder Social home page Coder Social logo

bharathi26 / django-foreignform Goto Github PK

View Code? Open in Web Editor NEW

This project forked from the-politico/django-foreignform

0.0 0.0 0.0 1.19 MB

Dynamic fieldsets for your Django ModelAdmin using JSON schema and react-jsonschema-form.

License: MIT License

Makefile 0.89% Python 53.16% CSS 3.57% JavaScript 37.21% HTML 5.16%

django-foreignform's Introduction

POLITICO

django-foreignform

PyPI version

Dynamic fieldsets for your Django ModelAdmin using JSON schema and react-jsonschema-form.

Define dynamic fieldsets with react-jsonschema-form. Store the schema on a foreign-keyed model. Serialize the fieldsets' back to a native Django JSON field in the admin.

Why this?

Let's explain by way of an example: At POLITICO, we use Django to model content.

Often we'll define a model that represents an individual piece of content and relate that model via a foreign key to another one representing a type of content. A common problem across those models are types that require a special field to contain information about a piece.

Think of a story template. It will have some fields in common with all other types of stories: a title, a byline, etc. So we define a story model that has those fields.

We know we have different types of stories -- feature pieces, breaking news items, whatever -- and so define a story template model to group story instances by a foreign key.

In Django, our models now look like this:

class StoryTemplate(models.Model):
  name = models.CharField()


class Story(models.Model):
  story_type = models.ForeignKey(StoryTemplate)
  headline = models.CharField()
  # etc.

But now we realize we need a template for a video story. Can do, but this template needs a new field: a video embed code. No other story type needs this field.

We now consider two options: 1) Add the embed field to our Story model, which will be useless for the 90% of our stories that are text-based. 2) Break out a new model, which will foreign key to Story and contain video-specific fields we can access via a reverse relationship.

We don't really like either of those options.

In our mind, the video embed field belongs to our StoryTemplate because it applies to all video stories. So why can't we simply add it there? Well, because the information contained in that field belongs to a Story instance, each with its own individual embed code.

What we really need is a way to define fields on the StoryTemplate model that can be filled out in the Story ModelAdmin.

With django-foreignform you can! We can use JSON Schema to define any fields specific to a template on our StoryTemplate model and then render those fields dynamically in a ModelAdmin for our Story model. As users fill out these dynamic fields, their values are serialized back to a JSON field on the Story model.

So instead our models look something like this:

class StoryTemplate(models.Model):
  name = models.CharField()
  json_schema = JSONField()


class Story(models.Model):
  story_type = models.ForeignKey(StoryTemplate)
  headline = models.CharField()
  form_data = JSONField()
  # etc.

We can then define our video field via JSON schema on the StoryTemplate like this:

{
  "type": "object",
  "properties": {
    "video": {
      "type": "string",
      "title": "Video embed code"
    }
  }
}

... which, once it's filled in by a user on a Story model, may then serialize to data like this:

{
  "video": "https://www.youtube.com/watch?v=wuK0f-Zur9A"
}
Upshot

A long way to say django-foreignform lets us write more complex models while keeping the relationships in our database very simple. It helps us avoid extra models to handle edge cases or cluttering up the models we have with rarely used fields.

Buyer beware

This library is very early days for us. It may not be ready for your own production needs.

Forms it creates definitely should not be used by anyone who's not a friend to your organization. While react-jsonschema-form gives us some light data validation options on the form it renders, you're trading against Django's robust model validation. It's also very easy for a bad actor to circumvent the form and insert values into the hidden JSON field.

For all those reasons, this library only renders forms in Django's admin, which should encourage you to only give access to trusted staff.

All that said, you should try it out! Pull requests welcome!

Requirements

  • PostgreSQL ≥ 9.4
  • Django ≥ 2.0

Quickstart

  1. Install the app.
$ pip install django-foreignform
  1. Add the app to your Django project and configure settings.
INSTALLED_APPS = [
    # ...
    'foreignform',
]
  1. Define a template model from our base class and an instance foreign-keyed to the first with a dedicated JSON field for your form data.
from django.contrib.postgres.fields import JSONField
from django.db import models

from foreignform.models import ForeignFormBaseModel

class StoryTemplate(ForeignFormBaseModel):
    name = models.CharField(max_length=100)
    # ...

class Story(models.Model):
    template = models.ForeignKey(StoryTemplate, on_delete=models.PROTECT)
    name = models.CharField(max_length=100)
    form_data = JSONField(blank=True, null=True)
    # ...
  1. Use our mixin to create a ModelAdmin for your foreign-keyed model with properties for the foreign key field and the JSON field for your form data.
from django.contrib import admin
from foreignform.mixins import ForeignFormAdminMixin
from .models import StoryTemplate, Story


class StoryAdmin(ForeignFormAdminMixin, admin.ModelAdmin):
    foreignform_foreign_key = 'template'
    foreignform_field = 'form_data'



admin.site.register(StoryTemplate)
admin.site.register(Story, StoryAdmin)
  1. In the admin for a template model, define some fields on your model using JSONSchema syntax and react-jsonschema-form's UI schema.

  1. In the admin for an instance, create an instance with a foreign key to the template model. Click Save and continue editing.

  1. With the foreign key saved, you can now fill out fields defined in the template model's JSON schema. Behind the scenes, the formset is being serialized and saved to your instance model's JSON field.

  1. Use the serialized JSON data from your form in your model's JSON field.
Story.objects.first().form_data

Developing

Running a development server

Developing python files? Move into example directory and run the development server with pipenv.

$ cd example
$ pipenv run python manage.py runserver

Developing static assets? Move into the pluggable app's staticapp directory and start the node development server, which will automatically proxy Django's development server.

$ cd foreignform/staticapp
$ gulp

Want to not worry about it? Use the shortcut make command.

$ make dev
Setting up a PostgreSQL database
  1. Run the make command to setup a fresh database.
$ make database
  1. Add a connection URL to the .env file.
DATABASE_URL="postgres://localhost:5432/foreignform"
  1. Run migrations from the example app.
$ cd example
$ pipenv run python manage.py migrate

django-foreignform's People

Contributors

hobbes7878 avatar cirotix avatar

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.