If someone actually wants to use it I can set aside some time within the
next week or two to actually open source the whole thing (docs + source on
github/pypi).

Here is an example of some of the basic functionality though:

*What the following code does:*
Creates a page for taking attendance of something that has 2 components, a
listing component that lists existing attendees and a entry component that
adds new people to the list.

We have javascript that disables the default form action and on form submit
submits via ajax. If there are errors, the form is displayed again with any
errors showing (over ajax), if there aren't errors, it resets the form and
also updates the listing component over ajax in a format like this (note,
though we haven't extended ourselves, it was made so that you could send
payloads other than "new_html" and make a custom handler for
"framework_example_attendance_entry" that could do something other than
simply dump new_html into the given div):
{
    "actions": {
        "framework_example_attendance_entry": {
            "component_key": "framework_example_attendance_entry",
            "new_html": "<form method=\"POST\"
                                action=\"/framework_example/\">
                            <div style=\"display:none\">
                                <input type=\"hidden\"
                                    name=\"csrfmiddlewaretoken\"
                                    value=\"....\">
                            </div>
                            <p><label for=\"id_name\">Name:</label>
                            <input id=\"id_name\" type=\"text\"
                                name=\"name\" maxlength="75" />
                            <input type=\"hidden\" name=\"page_key\"
                                value=\"framework_example_attendance_entry\"
                                id=\"id_page_key\" />
                            <input type=\"hidden\" name=\"param_key\"
                                id=\"id_param_key\" />
                            <input type=\"hidden\" name=\"version\"
                                value=\"1\" id=\"id_version\" /></p>
                            <input type=\"submit\">
                        </form>",
            "version": 1,
            "js_failure_mode": "no_warn_no_update"
        },
        "framework_example_listing": {
            "component_key": "framework_example_listing",
            "new_html": "<ul>
                            <li>George - Aug. 12, 2014, 1:46 p.m.</li>
                            <li>Smith - Aug. 12, 2014, 1:46 p.m.</li>
                            <li>Joseph - Aug. 12, 2014, 1:23 p.m. </li>
                            <li>Steve - Aug. 12, 2014, 1:22 p.m.</li>
                            <li>John - Aug. 12, 2014, 1:22 p.m.</li>
                            <li>Andy - Aug. 12, 2014, 12:09 p.m.</li>
                            <li>Sam - Aug. 12, 2014, 11:13 a.m.</li>
                        </ul>",
            "version": 1,
            "js_failure_mode": "no_warn_no_update"
        }
    }
}

*views.py:*

class AttendanceMixin(object):
    # We encourage using Mixins that contain @obj_cache decorated methods
    # that will (or in some cases may) be used by multiple components.
    @obj_cache
    def attendance_list(self):
        return list(AttendanceRecord.objects.order_by('-id'))

    @obj_cache
    def num_attendees(self):
        # This is free IFF we already need a list of attendees in the
        # request, otherwise  we should be using
        # `AttendanceRecord.objects.count()`

        # Also note that it is fine to chain @obj_cache decorated methods.
        return len(self.attendance_list)

class AttendanceEntryComponent(AttendanceMixin, Component):
    template_name = "framework_example/entry_component.html"

    def init(self):
        self.ctx.this_form_url = self.this_url()

        if not self.is_post():
            self.ctx.attendance_form = AttendanceRecordForm(
                **self.form_init())

    def handler(self, request):
        self.ctx.attendance_form = AttendanceRecordForm(request.POST,
                                                        **self.form_init())
        if self.ctx.attendance_form.is_valid():
            self.ctx.attendance_form.save()
            self.ctx.attendance_form = AttendanceRecordForm(
                **self.form_init())
            self.add_dependent_component(AttendanceListingComponent)
            return True

    def final(self):
        # The @obj_cache decorator turns methods into properties so note
        # that this isn't `self.num_attendees()`
        self.ctx.num_attendees = self.num_attendees

class AttendanceListingComponent(AttendanceMixin, Component):
    template_name = "framework_example/listing_component.html"

    def init(self):
        self.ctx.attendance_list = self.attendance_list

class AttendancePage(Page):
    template_name = "framework_example/attendance_page.html"

    def set_components(self):
        self.add_component(AttendanceListingComponent)

*urls.py:*
    component_url(r'^attendance_listing/$',
                  ComponentClass=AttendanceListingComponent,
                  name="framework_example_listing"),
    component_url(r'^$',
                  ComponentClass=AttendanceEntryComponent,
                  name="framework_example_attendance_entry",
                  PageClass=AttendancePage),


*templates/framework_example/entry_component.html:*

Add a new attendee (Currently {{ num_attendees }} attending)

<form method="POST" action="{{ this_form_url }}">
    {% csrf_token %}
    {{ attendance_form.as_p }}
    <input type="submit">
</form>

*templates/framework_example/listing_component.html:*
<ul>
    {% for attendance_record in attendance_list %}
        <li>
            {{ attendance_record.name }} - {{
attendance_record.arrival_time }}
        </li>
    {% endfor %}
</ul>

*templates/framework_example/attendance_page.html*
{% extends "base.html" %}

{% block content %}
    {% comment %}
        The surrounding div id follows a specific formula so it can be
        automatically updated on ajax requests: `cmp_<component_name>_id`
    {% endcomment %}
    <div id="cmp_framework_example_listing_id">
        {% comment %}
            Similarly, you can grab the rendered html from the component by
            asking for `component_name` from the dictionary of rendered html
            `components`:
        {% endcomment %}
        {{ components.framework_example_listing }}
    </div>

    <div id="cmp_framework_example_attendance_entry_id">
        {{ components.framework_example_attendance_entry }}
    </div>
{% endblock content %}


On Mon, Jun 1, 2015 at 11:54 PM, Emil Stenström <e...@kth.se> wrote:

> On Monday, 1 June 2015 19:12:36 UTC+2, Sam Solomon wrote:
>>
>> So a former co-worker with some help/guidance from me developed a
>> component system on top of Django that sounds sorta like what you are all
>> talking about. It's very complicated and I'm still not sure whether it was
>> ultimately a good idea to use or not, but it does make some things very
>> simple (and we have no plans to move away from it at this point after ~2
>> years of use). I'll post some snippets from our internal docs on it now and
>> if people are interested, I can explain more and possibly open source it
>> <snip>
>>
>
> Interesting! I would definitely want to see some code examples here. Could
> you show me how me more about how it works?
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/django-developers/FmBM8VdxJ08/unsubscribe
> .
> To unsubscribe from this group and all its topics, send an email to
> django-developers+unsubscr...@googlegroups.com.
> To post to this group, send email to django-developers@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-developers.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-developers/5e562720-9484-4e4f-9507-129d55a4cfce%40googlegroups.com
> <https://groups.google.com/d/msgid/django-developers/5e562720-9484-4e4f-9507-129d55a4cfce%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/CADGELX_0G%2BeyQLqzxa-enpVG_m10NeOcjyjiY_7b0c%2BbwHhqMQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to