Quantcast

Multiple models inside container

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Multiple models inside container

Lumir Jasiok
Hi,

right now I have small app with one model, one AddForm as is below:

class Awis(grok.Application, grok.Container):
     def __init__(self):
         super(Awis, self).__init__()
         self.title = "AWIS"
         self.store_id = 0

class IStore(interface.Interface):
     store_id = schema.Int(title=u'Store ID', default=1)
     title = schema.TextLine(title=u'Name', required=True)
     address = schema.Text(title=u'Address')
     storesman = schema.TextLine(title=u'Storesman', required=True)
     description = schema.Text(title=u'Description')

class Store(grok.Model):
     grok.implements(IStore)

class AddStore(grok.AddForm):
     grok.context(Awis)
     form_fields = grok.AutoFields(IStore).omit('store_id')

     @grok.action('Add Store')
     def add(self,**data):
         self.context.store_id = self.context.store_id + 1
         data['store_id'] = self.context.store_id
         store = Store()
         self.applyData(store,**data)
         store.store_id = self.context.store_id
         self.context[str(self.context.store_id)] = store
         self.context._p_changed = True
         self.redirect(self.url(store))

But now I want to add Employee class, that will be similar to Store
class. Inside Employee AddForm I want to save inside Awis context. After
that I will not be able to recognize which ID belongs to Store object
and Which to Employee object. How can I correctly save Store objects and
Employees objects inside Awis container and be able to recognize them.
Using dictionaries - self.context.stores and self.context.employees? -
but how can I access those dictionaries from TAL?

Or am I completely wrong and there is better way to do it?

Best Regards

Lumir

--
  Lumír Jasiok
  VSB-TU Ostrava - Computer centre
  Tel: +420 59 732 3189
  E-mail: [hidden email]
  http://www.vsb.cz

_______________________________________________
Grok-dev mailing list
[hidden email]
https://mail.zope.org/mailman/listinfo/grok-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Multiple models inside container

Martijn Faassen-2
On 03/17/2011 01:32 PM, Lumir Jasiok wrote:
[snip]
> But now I want to add Employee class, that will be similar to Store
> class. Inside Employee AddForm I want to save inside Awis context. After
> that I will not be able to recognize which ID belongs to Store object
> and Which to Employee object. How can I correctly save Store objects and
> Employees objects inside Awis container and be able to recognize them.
> Using dictionaries - self.context.stores and self.context.employees? -
> but how can I access those dictionaries from TAL?
>
> Or am I completely wrong and there is better way to do it?

There are different solutions.

You could create two containers and make them @grok.traversible and
store them in the Awis object, one for Employee and one for Store.  You
might need to set up the sub-containers in an event handler for the add
event to make it set up right; not sure it works in the __init__(). This
would, I think, be the simplest approach and makes sure your objects are
in different containers altogether. Container making explicit subclasses
for the subcontainers, such as EmployeeContainer and StoreContainer, so
that you can create specific views for them and such later.

Alternatively you could indeed store everything withint Awis. One way to
distinguish the two is to simply use Python's isinstance() and loop
through the things in the container in some helper method:

def get_employees(self):
   employees = []
   for value in self.values():
       if isinstance(value, Employee):
            employees.append(value)
   return employees

This won't be very fast if you have *many* employees or stores, though,
as it'll have to loop through them each time. Instead, you could
consider using the catalog. You can then index these things in the
catalog, and look them up quickly in the index. You'd probably have to
set up a "model_type"  (or whatever name you pick) attribute on the
Store and Employee classes that you can index first:

class Employee(...):
    model_type = 'employee'

setting up the catalog is something you need to google for.

Note that you can still use the catalog even if you spread things into
different containers as sketched out above.

Regards,

Martijn

_______________________________________________
Grok-dev mailing list
[hidden email]
https://mail.zope.org/mailman/listinfo/grok-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Multiple models inside container

Lumir Jasiok
On 3/21/11 4:53 PM, Martijn Faassen wrote:
On 03/17/2011 01:32 PM, Lumir Jasiok wrote:
[snip]
But now I want to add Employee class, that will be similar to Store
class. Inside Employee AddForm I want to save inside Awis context. After
that I will not be able to recognize which ID belongs to Store object
and Which to Employee object. How can I correctly save Store objects and
Employees objects inside Awis container and be able to recognize them.
Using dictionaries - self.context.stores and self.context.employees? -
but how can I access those dictionaries from TAL?

Or am I completely wrong and there is better way to do it?
There are different solutions.

You could create two containers and make them @grok.traversible and 
store them in the Awis object, one for Employee and one for Store.  You 
might need to set up the sub-containers in an event handler for the add 
event to make it set up right; not sure it works in the __init__(). This 
would, I think, be the simplest approach and makes sure your objects are 
in different containers altogether. Container making explicit subclasses 
for the subcontainers, such as EmployeeContainer and StoreContainer, so 
that you can create specific views for them and such later.

OK, I understand concept and I like it. This is what I looking for. But I am not familiar with grok.traversable(). Sorry for trouble you, but do you have some small example? Will be possible edit objects inside container using EditForm? AFIK grok.context() inside EditForm should be just Application or Model object types?
Alternatively you could indeed store everything withint Awis. One way to 
distinguish the two is to simply use Python's isinstance() and loop 
through the things in the container in some helper method:

def get_employees(self):
   employees = []
   for value in self.values():
       if isinstance(value, Employee):
            employees.append(value)
   return employees

Temporarily I fix it like this:

class AddStore(grok.AddForm):
    grok.context(Awis)
    form_fields = grok.AutoFields(IStore)

    @grok.action('Add Store')
    def add(self,**data):
        self.context.store_id = self.context.store_id + 1
        data['store_id'] = self.context.store_id
        store = Store()
        self.applyData(store,**data)
        name = "store-" + str(self.context.store_id)
        # Set the right store_id
        store.store_id = self.context.store_id
        self.context[name] = store
        self.context._p_changed = True
        return self.redirect(self.url(self.context))

class AddEmployee(grok.AddForm):
    grok.context(Awis)
    form_fields = grok.AutoFields(IEmployee)

    @grok.action('Add Employee')
    def add(self,**data):
        self.context.employee_id = self.context.employee_id + 1
        data['employee_id'] = self.context.employee_id
        employee = Employee()
        self.applyData(employee,**data)
        name = "employee-" + str(self.context.employee_id)
        self.context[name] = employee
        self.context._p_changed = True
        return self.redirect(self.url('employees'))

So I have different names and different ID's for different objects inside Awis context. But I have trouble on page template side. I am trying iterate over context/values and using conditional elements to display or not object.

stores.pt sample code:

 <body>
        <h1>Stores</h1>
        <tal:block repeat="store context/values">
        <div tal:condition="python:isinstance(store,Store)">
        <ul>
            <li tal:content="python:store">Object</li>
            <li tal:content="store/title">Title</li>
            <li tal:content="store/storesman">Storesman</li>
            <li tal:content="store/description">Description</li>
            <a tal:define="url python:view.url('deletestore')" tal:attributes="href string:${url}?store=${store/store_id}"/>Delete<a/>
            <a tal:attributes="href string:store-${store/store_id}/edit">Edit</a>
        </ul>
        </div>
        </tal:block>
        <a  href="./addstore">Add Store</a>
        <p />
        <a  href="./index">Main page</a>
    </body>

This code doesn't work. Problem is with isinstance(store,Store) evaluation. It always failed. I tried isinstance(store,context/Store) without success. Only working code is isinstance(store,object). But this is useless. How can I test if repeated object is Store or Employee object correctly inside page templates?

FYI, line:

<li tal:content="python:store">Object</li>

is evaluated as
  • <awis.app.Store object at 0x3bb4848>

Best Regards

Lumir
This won't be very fast if you have *many* employees or stores, though, 
as it'll have to loop through them each time. Instead, you could 
consider using the catalog. You can then index these things in the 
catalog, and look them up quickly in the index. You'd probably have to 
set up a "model_type"  (or whatever name you pick) attribute on the 
Store and Employee classes that you can index first:

class Employee(...):
    model_type = 'employee'

setting up the catalog is something you need to google for.

Note that you can still use the catalog even if you spread things into 
different containers as sketched out above.

Regards,

Martijn

_______________________________________________
Grok-dev mailing list
[hidden email]
https://mail.zope.org/mailman/listinfo/grok-dev


-- 
 Lumír Jasiok
 VSB-TU Ostrava - Computer centre
 Tel: +420 59 732 3189
 E-mail: [hidden email]
 http://www.vsb.cz 

_______________________________________________
Grok-dev mailing list
[hidden email]
https://mail.zope.org/mailman/listinfo/grok-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Multiple models inside container

Martijn Faassen-2
On 03/23/2011 01:24 PM, Lumir Jasiok wrote:

> OK, I understand concept and I like it. This is what I looking for. But
> I am not familiar with grok.traversable(). Sorry for trouble you, but do
> you have some small example? Will be possible edit objects inside
> container using EditForm?

Yes, it won't matter where the objects are, as long as the EditForm's
context is the objects you want to edit, it should work.

> AFIK grok.context() inside EditForm should be
> just Application or Model object types?

Generally for an edit form you'd want the context to be the object you
want to edit, and for an add form you'd want the context to be the
collection (container) of objects you want to add to.

For an example, check here:

http://grok.zope.org/doc/1.3/reference/directives.html#grok-traversable

but for containers, you'd basically do this:

class MyApplication(grok.Application, grok.Model):
     grok.traversable('foo')
     grok.traversable('bar')

     def __init__(self):
          self.foo = FooContainer()
          self.bar = BarContainer()


Now myapp/foo and myapp/bar are your containers. You'd probably have add
forms like this: myapp/foo/add and myapp/bar/add, and you'd have edit
forms like this myapp/foo/1553/edit and myapp/bar/515353/edit. You'd
make the add form for 'Foo' objects the context of FooContainer, and the
same for bar and BarContainer.

Note that as I said previously, you might need an event to set up these
containers instead, I'm not sure initialization will go nicely here -
not 100% sure.

You could also choose to let MyApplication itself be a container, in
which case you wouldn't need grok.traversable:

class MyApplication(grok.Application, grok.Container):
     def __init__(self):
          self['foo'] = FooContainer()
          self['bar'] = BarContainer()

but this design is a bit less nice, as really the application isn't
really a container people can add and remove things to.

[snip]
> This code doesn't work. Problem is with isinstance(store,Store)
> evaluation. It always failed. I tried isinstance(store,context/Store)
> without success. Only working code is isinstance(store,object). But this
> is useless. How can I test if repeated object is Store or Employee
> object correctly inside page templates?

I would never do this within a template. I'd always write a helper
method in Python to do this, and then call this from your template
instead. I'd simply make a method that returns all stores. That makes it
easier to test too. Page templates are restricted in various ways that I
just don't want to have to deal with. In this case I don't know where
the 'Store' class comes from in the template.

But anyway, if you change your application's design so that the stores
are in a separate container, things will become simpler.

Regards,

Martijn

_______________________________________________
Grok-dev mailing list
[hidden email]
https://mail.zope.org/mailman/listinfo/grok-dev
Loading...