Skip to content

Commit

Permalink
Our first Post/Redirect/Get
Browse files Browse the repository at this point in the history
  • Loading branch information
silviogutierrez committed Jul 7, 2018
1 parent 08294c6 commit 8bf2617
Show file tree
Hide file tree
Showing 15 changed files with 153 additions and 16 deletions.
25 changes: 22 additions & 3 deletions components/Widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,26 @@ interface BaseWidget {
attrs: {
id: string;
disabled?: boolean;
required?: boolean;
};
}

interface TextInput extends BaseWidget {
type: 'text';
template_name: 'django/forms/widgets/text.html';
value: string;
attrs: BaseWidget['attrs'] & {
maxlength?: number;
}
}

interface NumberInput extends BaseWidget {
type: 'number';
template_name: 'django/forms/widgets/number.html';
value: string;
attrs: BaseWidget['attrs'] & {
step: string;
}
}

type Optgroup = [
Expand Down Expand Up @@ -50,7 +63,7 @@ interface SelectMultiple extends Select {
}
}

export type WidgetType = TextInput|Select|SelectMultiple;
export type WidgetType = TextInput|NumberInput|Select|SelectMultiple;

interface Props {
widget: WidgetType;
Expand Down Expand Up @@ -83,17 +96,23 @@ export const Widget = (props: Props) => {
*/
// return <div>I am a select single</div>;
const value = isMultiple(widget) ? widget.value : (widget.value[0] || '');
return <select name={widget.name} multiple={isMultiple(widget)} defaultValue={value}>
return <select
name={widget.name}
multiple={isMultiple(widget)}
defaultValue={value}
>
{widget.optgroups.map((optgroup, index) =>
<option key={index} value={getValue(optgroup)}>{optgroup[1][0].label}</option>
)}
</select>;
}
case "django/forms/widgets/number.html":
case "django/forms/widgets/text.html": {
return <input defaultValue={widget.value || ""} name={widget.name} />;
return <input type={widget.type} defaultValue={widget.value || ""} name={widget.name} />;
// return <div>I am a text</div>;
}
default: {
console.log(widget);
const _exhaustiveCheck: never = widget;
throw new Error('Cannot happen');
}
Expand Down
12 changes: 4 additions & 8 deletions index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,10 @@ const ssrProxy = proxy('localhost:8000', {
}

const responseAsJSON: any = JSON.parse(proxyResData.toString('utf8'));
const {template_name, props, ...globalProps} = responseAsJSON;
const Template = require(`./templates/${template_name}.tsx`).default;
const propsForTemplate = {
...globalProps,
...props,
};
const rendered = ReactDOMServer.renderToString(<Template {...propsForTemplate} />);
return renderPage({html: rendered, css: '', props: propsForTemplate});
const props = responseAsJSON;
const Template = require(`./templates/${props.template_name}.tsx`).default;
const rendered = ReactDOMServer.renderToString(<Template {...props} />);
return renderPage({html: rendered, css: '', props});
},
});

Expand Down
Binary file modified server/db.sqlite3
Binary file not shown.
1 change: 1 addition & 0 deletions server/server/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

INSTALLED_APPS = [
'django_extensions',
'server.testing',

'django.contrib.admin',
'django.contrib.auth',
Expand Down
Empty file.
3 changes: 3 additions & 0 deletions server/server/testing/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
5 changes: 5 additions & 0 deletions server/server/testing/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class TestingConfig(AppConfig):
name = 'testing'
32 changes: 32 additions & 0 deletions server/server/testing/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Generated by Django 2.0.7 on 2018-07-07 14:59

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
]

operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
],
),
migrations.CreateModel(
name='Widget',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('price', models.DecimalField(decimal_places=2, max_digits=10)),
('type', models.CharField(choices=[('cheap', 'Cheap'), ('expensive', 'Expensive')], max_length=100)),
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='testing.Category')),
],
),
]
Empty file.
23 changes: 23 additions & 0 deletions server/server/testing/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django.db import models

import decimal


class Category(models.Model):
name: str = models.CharField(max_length=200)

def __str__(self) -> str:
return self.name


class Widget(models.Model):
name: str = models.CharField(max_length=200)
category: Category = models.ForeignKey(Category, on_delete=models.CASCADE)
price: decimal.Decimal = models.DecimalField(decimal_places=2, max_digits=10)
type: str = models.CharField(max_length=100, choices=(
('cheap', 'Cheap'),
('expensive', 'Expensive'),
))

def __str__(self) -> str:
return self.name
3 changes: 3 additions & 0 deletions server/server/testing/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
3 changes: 3 additions & 0 deletions server/server/testing/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.shortcuts import render

# Create your views here.
1 change: 1 addition & 0 deletions server/server/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from . import views

urlpatterns = [
path('record/', views.test_record),
path('test/', views.test),
path('form/', views.test_form),
path('admin/', admin.site.urls),
Expand Down
51 changes: 47 additions & 4 deletions server/server/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@

from typing import Any, NamedTuple

from server.testing import models

import simplejson


class JSXResponse(NamedTuple):
csrf_token: str
template_name: str
props: Any
class JSXResponse:
def __init__(self, *, csrf_token: str, template_name: str, props: Any) -> None:
self.props = {
'csrf_token': csrf_token,
'template_name': template_name,
**props,
}

def as_json(self) -> Any:
return simplejson.dumps(self.props)


def test(request: HttpRequest) -> HttpResponse:
Expand All @@ -28,6 +36,41 @@ def render(self, template_name, context, request=None):
return simplejson.dumps(context)


def test_record(request: HttpRequest) -> HttpResponse:
from django import forms

class WidgetForm(forms.ModelForm):
class Meta:
model = models.Widget
fields = '__all__'

if request.method == 'POST':
form = WidgetForm(request.POST, renderer=SSRFormRenderer())

if form.is_valid():
form.save()
return redirect(request.path)
else:
form = WidgetForm(renderer=SSRFormRenderer())

serialized_form = {
'errors': form.errors,
'fields': [simplejson.loads(str(field)) for field in form],
}

response = JSXResponse(
template_name='FormView',
csrf_token=get_token(request),
props={
'form': serialized_form,
'widget_list': [
widget.name for widget in models.Widget.objects.all()
],
},
)
return HttpResponse(response.as_json(), content_type='application/ssr+json')


def test_form(request: HttpRequest) -> HttpResponse:
from django import forms
from django.contrib.auth.models import User
Expand Down
10 changes: 9 additions & 1 deletion templates/FormView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ import {FormType, Form} from '../components/Form';

interface Props {
form: FormType;
widget_list: string[];
csrf_token: string;
}

export default (props: Props) => <Form csrf_token={props.csrf_token} form={props.form} />;
export default (props: Props) => <div>
<ul>
{props.widget_list.map(widget =>
<li key={widget}>{widget}</li>
)}
</ul>
<Form csrf_token={props.csrf_token} form={props.form} />
</div>;

0 comments on commit 8bf2617

Please sign in to comment.