summaryrefslogtreecommitdiff
path: root/python-djax.spec
blob: 22730d05e553d9029208d6ecb9ed3e60ce8ec16b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
%global _empty_manifest_terminate_build 0
Name:		python-Djax
Version:	0.8.6
Release:	1
Summary:	Integrates Django projects with Axilent.
License:	BSD
URL:		http://github.com/Axilent/Djax
Source0:	https://mirrors.nju.edu.cn/pypi/web/packages/44/1c/c49ec9129f50c2bc458bb9beb1dbd5b6b67c568b41d3744be43d1031fbce/Djax-0.8.6.tar.gz
BuildArch:	noarch


%description
**Django / ACE Integration**
Djax integrates the Django web framework with `Axilent
ACE <http://www.axilent.com/products/ace/>`__. ACE is a sophisticated
content targeting system that can be used for product recommendations,
related content, personalization and contextual advertising.
Djax links Django models with ACE content types, enabling the use of ACE
as a CMS for a Django website. It also provides easy integration with
ACE's targeting Content Channels, and provides integration with ACE's
user profiling system.
Installation
~~~~~~~~~~~~
To install Djax with Pip:
    pip install Djax
Then, add ``djax`` to your ``INSTALLED_APPS``.
Finally, you will need to ``syncdb`` to generate Djax's tables.
Integrating ACE Published Content With Django
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order to use content that is authored our sourced in ACE in a Django
website, integrate the desired Django model with Djax using the
ACEContent mixin.
    # your-app/models.py
    from django.db import models
    from djax.content import ACEContent
    class Article(models.Model,ACEContent):
         title = models.CharField(max_length=100)
         body = models.TextField()
         class ACE:
             content_type = 'Article'
             field_map = {
                 'title':'title',
                 'body':'body',
             }
Several important things are happening here:
1. In addition to inheriting from ``models.Model`` like an ordinary
   Django model, the Article class also inherits from ``ACEContent``.
   This will allow Djax to identify it as a local type of content that
   should be bound to an ACE Content Type.
2. In the ``ACE`` inner class, the ``content_type`` attribute identifies
   the ACE Content Type with which this model should be associated.
3. In the ``ACE inner class`` the ``field_map`` dictionary defines the
   mappings between the ACE Content Type fields (the keys in the
   dictionary) and the local model's fields (the values in the
   dictionary).
When Djax syncs with ACE, it will create or update this model with the
mapped content from ACE.
Managing Foreign Key Relations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ACE is not a relational database, and accordingly does not hold content
to the same level of integral rigor as an RDBMS. However, it does
provide some means to directly link one content item to another using a
field type called a **Content Link**.
Djax provides a way to convert an ACE Content Link into a Django foreign
key relationship. Let's say you have a local model that has an Author
model and an Article model. The Article model has a foriegn key field
that points to the Author model. In ACE, the Article Content Type would
have a Content Link field that would be used to point at an author.
The integration can be implemented without any special work using Djax:
    class Author(models.Model,ACEContent):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
        class ACE:
            content_type = 'Author'
            field_map = {
                'first_name':'first_name',
                'last_name':'last_name',
            }
      class Article(models.Model,ACEContent):
          author = models.ForeignKey(model=Author,related_name='articles')
          title = models.CharField(max_length=100)
          body = models.TextField()
          class ACE:
             content_type = 'Article'
             field_map = {
                 'author':'author',
                 'title':'title',
                 'body':'body',
             }
During a sync, incoming Content Link data from ACE will be enough to
alert Djax to look for a local model-to-ACE Content Type mapping, and
create a foreign key association in the local models.
Because the local model Article does not allow Article objects to exist
in the database without an associated Author, it is important to ensure
that the Author object is sync'd to the local database first. In a bulk
sync this will be taken care of automatically, but when syncing once
content item at a time, an error will occur if the Article object is
sync'd before the associated Author object.
Nullable Foreign Key Relations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
What if a foreign key relationship is nullable? In the example given
above, what if not all Articles have Authors? It's not a problem in ACE,
just leave the appropriate Content Link field empty. But an additional
step is required with Djax integration:
      class Article(models.Model,ACEContent):
          author = models.ForeignKey(model=Author,null=True,related_name='articles')
          title = models.CharField(max_length=100)
          body = models.TextField()
          class ACE:
             content_type = 'Article'
             field_map = {
                 'author':NullableForeignKeyConverter('author'),
                 'title':'title',
                 'body':'body',
             }
There are two changes in the Article model. First the author field has
been marked ``null=True`` to indicate to Django that the Article model
may not have an Author.
Secondly, the simple string ('author') indicating that the author field
in the incoming content from ACE should be mapped to the local author
field has been replaced by a ``NullableForeignKeyConverter`` object.
This is an indication to Djax that it should apply a special process to
the incoming data: either find a local model that corresponds to the
supplied Content Link data, or leave the field null.
Managing Many-to-Many Relations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ACE can also handle many-to-many relations using the Content Link List
field type. Let's say we have a local model that defines a many-to-many
relation between Publication and Author objects. In ACE, the Author
object would have a publication field that was a Content Link List that
would be used to associate it with Publications.
To implement the integration in Djax we would do this:
    class Publication(models.Model,ACEContent):
        name = models.CharField(max_length=100)
        class ACE:
            content_type = 'Publication'
            field_map = {
                'name':'name',
            }
    class Author(models.Model,ACEContent):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
        publications = models.ManyToManyField(Publication,related_name='authors')
        class ACE:
            content_type = 'Author'
            field_map = {
                'first_name':'first_name',
                'last_name':'last_name',
                'publications':M2MFieldConverter('publications'),
            }
In the Author model's ``ACE`` inner class, we have specified the
``M2MFieldConverter`` for the publications field. This lets Djax know to
convert incoming Content Link List data into a local many-to-many
relation.
Implementing Your Own Field Converters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The default behavior of a field map is to simply take the value from the
incoming ACE content and assign that value to the recipient local model.
This behavior can be overridden with the use of a *FieldConverter*.
A FieldConverter is an object that is placed as a value to the
corresponding ACE content field key, within the field map. The
FieldConverter is just an object (it does not require any particular
parent class). Djax will look for two specific methods on the field
converter object: ``to_local_model`` and ``to_ace``, and the name of the
local model field, defined as ``field``.
Simple Example:
    class AuthorFieldConverter(object):
        """Field converter changes string to related author (for article) and vice versa."""
        field = 'author'
        def to_local_model(self,ace_content,ace_field_value):
            """String to related model."""
            return Author.objects.get(name=ace_field_value)
        def to_ace(self,local_model):
            """Related model to string."""
            return local_model.author.name
In this case the field converter looks up a related model by name and
returns the related model as the value to assign to the local model.
A field converter may be marked as **deferred**, in which case Djax will
ensure that the local model is created *before* the conversion method is
called, and will pass the local model into the conversion method as an
argument.
With deferred converters, the return value for the ``to_local_model``
method is ignored. It is up to the method to associate the value to the
local model.
Parent / Child Deferred Example:
    class MusicLabelCatalogConverter(object):
        """Converts the bands signed to the parent label."""
        field = 'bands'
        deferred = True
        def to_local_model(self,ace_content,ace_field_value,local_model):
            """Gets or creates associated local band objects. Ace provides a list of band names."""
            for band_name in ace_field_value:
                Band.objects.get_or_create(label=local_model,name=band_name)
            # clean up unassociated bands
            [band.delete() for band in local_model.bands.exclude(name__in=ace_field_value)]
        def to_ace(self,local_model):
            """Returns a list of band names for ace."""
            return [band.name for band in local_model.bands.all()]
ACEContent Methods
~~~~~~~~~~~~~~~~~~
A Django model that also inherits from ACEContent will have several
additional methods that allow it to be programmatically managed from a
Django app, if desired.
ACEContent.get\_axilent\_content\_key
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Returns the local model's ACE content key. If the content does not exist
within the ACE account, it will return None. The content key is a GUID
rendered in hex format.
ACEContent.get\_axilent\_content\_type
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Returns the name of the ACE Content Type for the model.
ACEContent.sync\_with\_axilent
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Forces the local model to update from content from ACE. If there is no
corresponding content item in the ACE account, this method will do
nothing.
ACEContent.to\_content\_dict
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Returns content values as a dictionary according to the ``field_map``.
ACEContent.push\_to\_library
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Pushes the local values of the content into the associated ACE library.
This method returns a 2-tuple of booleans, indicating 1. if the library
was updated and 2. if a new content item was created in the library.
ACEContent.push\_to\_graphstack
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Puhes the local values of the content directly into the associated
GraphStack. A GraphStack in ACE is a logical container for deployed or
published content.
ACEContent.archive
^^^^^^^^^^^^^^^^^^
Removes the content from any GraphStack where it has been deployed.
ACEContent.live\_delete
^^^^^^^^^^^^^^^^^^^^^^^
Removes the associated ACE content item from the active GraphStack where
it is deployed.
ACEContent.tag
^^^^^^^^^^^^^^
Tags the content item within the associated ACE library.
ACEContent.detag
^^^^^^^^^^^^^^^^
De-tags the content item within the associated ACE library.
ACEContent.live\_tag
^^^^^^^^^^^^^^^^^^^^
Tags the content item where it has been deployed in the associated
GraphStack.
ACEContent.live\_detag
^^^^^^^^^^^^^^^^^^^^^^
De-tags the content item where it has been deployed in the associated
GraphStack.
ACEContent.reindex\_search
^^^^^^^^^^^^^^^^^^^^^^^^^^
Forces search re-indexing of the deployed associated content.
ACEContent.trigger\_affinity
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sends an affinity trigger for this content to ACE.
ACEContent.trigger\_ban
^^^^^^^^^^^^^^^^^^^^^^^
Sends a ban trigger for this content to ACE.
Setting Up Djax and ACE to Handle User-Generated Content
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A common scenario is User Generated Content (UGC), in which user's of
the website create content, in the form of Django models, which then
needs to be pushed back into the ACE library for administrative review.
Djax and ACE now support this round-trip model for content.
In the ACE project, first create a new **Content Source** for the
Content Type that you want to round-trip. Content Sources are found in
the settings panel, for each content type under the Content Types
section of the ACE project.
The new Content Source should be of the type **Djax User Generated
Content**. When creating the Content Source, you will need to set the
refresh interval, the URL pointing to the Djax install, and an auth
token.
In your code, you set up your model as ``ACEContent`` as usual, defining
the ACE content type and the field map in the ``ACE`` subclass.
Everytime the Content Source passes the refresh interval, it will query
your Djax install. At this point the Djax install will push the content
into the ACE library, either creating new content items or updating
existing ones.

%package -n python3-Djax
Summary:	Integrates Django projects with Axilent.
Provides:	python-Djax
BuildRequires:	python3-devel
BuildRequires:	python3-setuptools
BuildRequires:	python3-pip
%description -n python3-Djax
**Django / ACE Integration**
Djax integrates the Django web framework with `Axilent
ACE <http://www.axilent.com/products/ace/>`__. ACE is a sophisticated
content targeting system that can be used for product recommendations,
related content, personalization and contextual advertising.
Djax links Django models with ACE content types, enabling the use of ACE
as a CMS for a Django website. It also provides easy integration with
ACE's targeting Content Channels, and provides integration with ACE's
user profiling system.
Installation
~~~~~~~~~~~~
To install Djax with Pip:
    pip install Djax
Then, add ``djax`` to your ``INSTALLED_APPS``.
Finally, you will need to ``syncdb`` to generate Djax's tables.
Integrating ACE Published Content With Django
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order to use content that is authored our sourced in ACE in a Django
website, integrate the desired Django model with Djax using the
ACEContent mixin.
    # your-app/models.py
    from django.db import models
    from djax.content import ACEContent
    class Article(models.Model,ACEContent):
         title = models.CharField(max_length=100)
         body = models.TextField()
         class ACE:
             content_type = 'Article'
             field_map = {
                 'title':'title',
                 'body':'body',
             }
Several important things are happening here:
1. In addition to inheriting from ``models.Model`` like an ordinary
   Django model, the Article class also inherits from ``ACEContent``.
   This will allow Djax to identify it as a local type of content that
   should be bound to an ACE Content Type.
2. In the ``ACE`` inner class, the ``content_type`` attribute identifies
   the ACE Content Type with which this model should be associated.
3. In the ``ACE inner class`` the ``field_map`` dictionary defines the
   mappings between the ACE Content Type fields (the keys in the
   dictionary) and the local model's fields (the values in the
   dictionary).
When Djax syncs with ACE, it will create or update this model with the
mapped content from ACE.
Managing Foreign Key Relations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ACE is not a relational database, and accordingly does not hold content
to the same level of integral rigor as an RDBMS. However, it does
provide some means to directly link one content item to another using a
field type called a **Content Link**.
Djax provides a way to convert an ACE Content Link into a Django foreign
key relationship. Let's say you have a local model that has an Author
model and an Article model. The Article model has a foriegn key field
that points to the Author model. In ACE, the Article Content Type would
have a Content Link field that would be used to point at an author.
The integration can be implemented without any special work using Djax:
    class Author(models.Model,ACEContent):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
        class ACE:
            content_type = 'Author'
            field_map = {
                'first_name':'first_name',
                'last_name':'last_name',
            }
      class Article(models.Model,ACEContent):
          author = models.ForeignKey(model=Author,related_name='articles')
          title = models.CharField(max_length=100)
          body = models.TextField()
          class ACE:
             content_type = 'Article'
             field_map = {
                 'author':'author',
                 'title':'title',
                 'body':'body',
             }
During a sync, incoming Content Link data from ACE will be enough to
alert Djax to look for a local model-to-ACE Content Type mapping, and
create a foreign key association in the local models.
Because the local model Article does not allow Article objects to exist
in the database without an associated Author, it is important to ensure
that the Author object is sync'd to the local database first. In a bulk
sync this will be taken care of automatically, but when syncing once
content item at a time, an error will occur if the Article object is
sync'd before the associated Author object.
Nullable Foreign Key Relations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
What if a foreign key relationship is nullable? In the example given
above, what if not all Articles have Authors? It's not a problem in ACE,
just leave the appropriate Content Link field empty. But an additional
step is required with Djax integration:
      class Article(models.Model,ACEContent):
          author = models.ForeignKey(model=Author,null=True,related_name='articles')
          title = models.CharField(max_length=100)
          body = models.TextField()
          class ACE:
             content_type = 'Article'
             field_map = {
                 'author':NullableForeignKeyConverter('author'),
                 'title':'title',
                 'body':'body',
             }
There are two changes in the Article model. First the author field has
been marked ``null=True`` to indicate to Django that the Article model
may not have an Author.
Secondly, the simple string ('author') indicating that the author field
in the incoming content from ACE should be mapped to the local author
field has been replaced by a ``NullableForeignKeyConverter`` object.
This is an indication to Djax that it should apply a special process to
the incoming data: either find a local model that corresponds to the
supplied Content Link data, or leave the field null.
Managing Many-to-Many Relations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ACE can also handle many-to-many relations using the Content Link List
field type. Let's say we have a local model that defines a many-to-many
relation between Publication and Author objects. In ACE, the Author
object would have a publication field that was a Content Link List that
would be used to associate it with Publications.
To implement the integration in Djax we would do this:
    class Publication(models.Model,ACEContent):
        name = models.CharField(max_length=100)
        class ACE:
            content_type = 'Publication'
            field_map = {
                'name':'name',
            }
    class Author(models.Model,ACEContent):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
        publications = models.ManyToManyField(Publication,related_name='authors')
        class ACE:
            content_type = 'Author'
            field_map = {
                'first_name':'first_name',
                'last_name':'last_name',
                'publications':M2MFieldConverter('publications'),
            }
In the Author model's ``ACE`` inner class, we have specified the
``M2MFieldConverter`` for the publications field. This lets Djax know to
convert incoming Content Link List data into a local many-to-many
relation.
Implementing Your Own Field Converters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The default behavior of a field map is to simply take the value from the
incoming ACE content and assign that value to the recipient local model.
This behavior can be overridden with the use of a *FieldConverter*.
A FieldConverter is an object that is placed as a value to the
corresponding ACE content field key, within the field map. The
FieldConverter is just an object (it does not require any particular
parent class). Djax will look for two specific methods on the field
converter object: ``to_local_model`` and ``to_ace``, and the name of the
local model field, defined as ``field``.
Simple Example:
    class AuthorFieldConverter(object):
        """Field converter changes string to related author (for article) and vice versa."""
        field = 'author'
        def to_local_model(self,ace_content,ace_field_value):
            """String to related model."""
            return Author.objects.get(name=ace_field_value)
        def to_ace(self,local_model):
            """Related model to string."""
            return local_model.author.name
In this case the field converter looks up a related model by name and
returns the related model as the value to assign to the local model.
A field converter may be marked as **deferred**, in which case Djax will
ensure that the local model is created *before* the conversion method is
called, and will pass the local model into the conversion method as an
argument.
With deferred converters, the return value for the ``to_local_model``
method is ignored. It is up to the method to associate the value to the
local model.
Parent / Child Deferred Example:
    class MusicLabelCatalogConverter(object):
        """Converts the bands signed to the parent label."""
        field = 'bands'
        deferred = True
        def to_local_model(self,ace_content,ace_field_value,local_model):
            """Gets or creates associated local band objects. Ace provides a list of band names."""
            for band_name in ace_field_value:
                Band.objects.get_or_create(label=local_model,name=band_name)
            # clean up unassociated bands
            [band.delete() for band in local_model.bands.exclude(name__in=ace_field_value)]
        def to_ace(self,local_model):
            """Returns a list of band names for ace."""
            return [band.name for band in local_model.bands.all()]
ACEContent Methods
~~~~~~~~~~~~~~~~~~
A Django model that also inherits from ACEContent will have several
additional methods that allow it to be programmatically managed from a
Django app, if desired.
ACEContent.get\_axilent\_content\_key
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Returns the local model's ACE content key. If the content does not exist
within the ACE account, it will return None. The content key is a GUID
rendered in hex format.
ACEContent.get\_axilent\_content\_type
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Returns the name of the ACE Content Type for the model.
ACEContent.sync\_with\_axilent
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Forces the local model to update from content from ACE. If there is no
corresponding content item in the ACE account, this method will do
nothing.
ACEContent.to\_content\_dict
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Returns content values as a dictionary according to the ``field_map``.
ACEContent.push\_to\_library
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Pushes the local values of the content into the associated ACE library.
This method returns a 2-tuple of booleans, indicating 1. if the library
was updated and 2. if a new content item was created in the library.
ACEContent.push\_to\_graphstack
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Puhes the local values of the content directly into the associated
GraphStack. A GraphStack in ACE is a logical container for deployed or
published content.
ACEContent.archive
^^^^^^^^^^^^^^^^^^
Removes the content from any GraphStack where it has been deployed.
ACEContent.live\_delete
^^^^^^^^^^^^^^^^^^^^^^^
Removes the associated ACE content item from the active GraphStack where
it is deployed.
ACEContent.tag
^^^^^^^^^^^^^^
Tags the content item within the associated ACE library.
ACEContent.detag
^^^^^^^^^^^^^^^^
De-tags the content item within the associated ACE library.
ACEContent.live\_tag
^^^^^^^^^^^^^^^^^^^^
Tags the content item where it has been deployed in the associated
GraphStack.
ACEContent.live\_detag
^^^^^^^^^^^^^^^^^^^^^^
De-tags the content item where it has been deployed in the associated
GraphStack.
ACEContent.reindex\_search
^^^^^^^^^^^^^^^^^^^^^^^^^^
Forces search re-indexing of the deployed associated content.
ACEContent.trigger\_affinity
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sends an affinity trigger for this content to ACE.
ACEContent.trigger\_ban
^^^^^^^^^^^^^^^^^^^^^^^
Sends a ban trigger for this content to ACE.
Setting Up Djax and ACE to Handle User-Generated Content
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A common scenario is User Generated Content (UGC), in which user's of
the website create content, in the form of Django models, which then
needs to be pushed back into the ACE library for administrative review.
Djax and ACE now support this round-trip model for content.
In the ACE project, first create a new **Content Source** for the
Content Type that you want to round-trip. Content Sources are found in
the settings panel, for each content type under the Content Types
section of the ACE project.
The new Content Source should be of the type **Djax User Generated
Content**. When creating the Content Source, you will need to set the
refresh interval, the URL pointing to the Djax install, and an auth
token.
In your code, you set up your model as ``ACEContent`` as usual, defining
the ACE content type and the field map in the ``ACE`` subclass.
Everytime the Content Source passes the refresh interval, it will query
your Djax install. At this point the Djax install will push the content
into the ACE library, either creating new content items or updating
existing ones.

%package help
Summary:	Development documents and examples for Djax
Provides:	python3-Djax-doc
%description help
**Django / ACE Integration**
Djax integrates the Django web framework with `Axilent
ACE <http://www.axilent.com/products/ace/>`__. ACE is a sophisticated
content targeting system that can be used for product recommendations,
related content, personalization and contextual advertising.
Djax links Django models with ACE content types, enabling the use of ACE
as a CMS for a Django website. It also provides easy integration with
ACE's targeting Content Channels, and provides integration with ACE's
user profiling system.
Installation
~~~~~~~~~~~~
To install Djax with Pip:
    pip install Djax
Then, add ``djax`` to your ``INSTALLED_APPS``.
Finally, you will need to ``syncdb`` to generate Djax's tables.
Integrating ACE Published Content With Django
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order to use content that is authored our sourced in ACE in a Django
website, integrate the desired Django model with Djax using the
ACEContent mixin.
    # your-app/models.py
    from django.db import models
    from djax.content import ACEContent
    class Article(models.Model,ACEContent):
         title = models.CharField(max_length=100)
         body = models.TextField()
         class ACE:
             content_type = 'Article'
             field_map = {
                 'title':'title',
                 'body':'body',
             }
Several important things are happening here:
1. In addition to inheriting from ``models.Model`` like an ordinary
   Django model, the Article class also inherits from ``ACEContent``.
   This will allow Djax to identify it as a local type of content that
   should be bound to an ACE Content Type.
2. In the ``ACE`` inner class, the ``content_type`` attribute identifies
   the ACE Content Type with which this model should be associated.
3. In the ``ACE inner class`` the ``field_map`` dictionary defines the
   mappings between the ACE Content Type fields (the keys in the
   dictionary) and the local model's fields (the values in the
   dictionary).
When Djax syncs with ACE, it will create or update this model with the
mapped content from ACE.
Managing Foreign Key Relations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ACE is not a relational database, and accordingly does not hold content
to the same level of integral rigor as an RDBMS. However, it does
provide some means to directly link one content item to another using a
field type called a **Content Link**.
Djax provides a way to convert an ACE Content Link into a Django foreign
key relationship. Let's say you have a local model that has an Author
model and an Article model. The Article model has a foriegn key field
that points to the Author model. In ACE, the Article Content Type would
have a Content Link field that would be used to point at an author.
The integration can be implemented without any special work using Djax:
    class Author(models.Model,ACEContent):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
        class ACE:
            content_type = 'Author'
            field_map = {
                'first_name':'first_name',
                'last_name':'last_name',
            }
      class Article(models.Model,ACEContent):
          author = models.ForeignKey(model=Author,related_name='articles')
          title = models.CharField(max_length=100)
          body = models.TextField()
          class ACE:
             content_type = 'Article'
             field_map = {
                 'author':'author',
                 'title':'title',
                 'body':'body',
             }
During a sync, incoming Content Link data from ACE will be enough to
alert Djax to look for a local model-to-ACE Content Type mapping, and
create a foreign key association in the local models.
Because the local model Article does not allow Article objects to exist
in the database without an associated Author, it is important to ensure
that the Author object is sync'd to the local database first. In a bulk
sync this will be taken care of automatically, but when syncing once
content item at a time, an error will occur if the Article object is
sync'd before the associated Author object.
Nullable Foreign Key Relations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
What if a foreign key relationship is nullable? In the example given
above, what if not all Articles have Authors? It's not a problem in ACE,
just leave the appropriate Content Link field empty. But an additional
step is required with Djax integration:
      class Article(models.Model,ACEContent):
          author = models.ForeignKey(model=Author,null=True,related_name='articles')
          title = models.CharField(max_length=100)
          body = models.TextField()
          class ACE:
             content_type = 'Article'
             field_map = {
                 'author':NullableForeignKeyConverter('author'),
                 'title':'title',
                 'body':'body',
             }
There are two changes in the Article model. First the author field has
been marked ``null=True`` to indicate to Django that the Article model
may not have an Author.
Secondly, the simple string ('author') indicating that the author field
in the incoming content from ACE should be mapped to the local author
field has been replaced by a ``NullableForeignKeyConverter`` object.
This is an indication to Djax that it should apply a special process to
the incoming data: either find a local model that corresponds to the
supplied Content Link data, or leave the field null.
Managing Many-to-Many Relations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ACE can also handle many-to-many relations using the Content Link List
field type. Let's say we have a local model that defines a many-to-many
relation between Publication and Author objects. In ACE, the Author
object would have a publication field that was a Content Link List that
would be used to associate it with Publications.
To implement the integration in Djax we would do this:
    class Publication(models.Model,ACEContent):
        name = models.CharField(max_length=100)
        class ACE:
            content_type = 'Publication'
            field_map = {
                'name':'name',
            }
    class Author(models.Model,ACEContent):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
        publications = models.ManyToManyField(Publication,related_name='authors')
        class ACE:
            content_type = 'Author'
            field_map = {
                'first_name':'first_name',
                'last_name':'last_name',
                'publications':M2MFieldConverter('publications'),
            }
In the Author model's ``ACE`` inner class, we have specified the
``M2MFieldConverter`` for the publications field. This lets Djax know to
convert incoming Content Link List data into a local many-to-many
relation.
Implementing Your Own Field Converters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The default behavior of a field map is to simply take the value from the
incoming ACE content and assign that value to the recipient local model.
This behavior can be overridden with the use of a *FieldConverter*.
A FieldConverter is an object that is placed as a value to the
corresponding ACE content field key, within the field map. The
FieldConverter is just an object (it does not require any particular
parent class). Djax will look for two specific methods on the field
converter object: ``to_local_model`` and ``to_ace``, and the name of the
local model field, defined as ``field``.
Simple Example:
    class AuthorFieldConverter(object):
        """Field converter changes string to related author (for article) and vice versa."""
        field = 'author'
        def to_local_model(self,ace_content,ace_field_value):
            """String to related model."""
            return Author.objects.get(name=ace_field_value)
        def to_ace(self,local_model):
            """Related model to string."""
            return local_model.author.name
In this case the field converter looks up a related model by name and
returns the related model as the value to assign to the local model.
A field converter may be marked as **deferred**, in which case Djax will
ensure that the local model is created *before* the conversion method is
called, and will pass the local model into the conversion method as an
argument.
With deferred converters, the return value for the ``to_local_model``
method is ignored. It is up to the method to associate the value to the
local model.
Parent / Child Deferred Example:
    class MusicLabelCatalogConverter(object):
        """Converts the bands signed to the parent label."""
        field = 'bands'
        deferred = True
        def to_local_model(self,ace_content,ace_field_value,local_model):
            """Gets or creates associated local band objects. Ace provides a list of band names."""
            for band_name in ace_field_value:
                Band.objects.get_or_create(label=local_model,name=band_name)
            # clean up unassociated bands
            [band.delete() for band in local_model.bands.exclude(name__in=ace_field_value)]
        def to_ace(self,local_model):
            """Returns a list of band names for ace."""
            return [band.name for band in local_model.bands.all()]
ACEContent Methods
~~~~~~~~~~~~~~~~~~
A Django model that also inherits from ACEContent will have several
additional methods that allow it to be programmatically managed from a
Django app, if desired.
ACEContent.get\_axilent\_content\_key
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Returns the local model's ACE content key. If the content does not exist
within the ACE account, it will return None. The content key is a GUID
rendered in hex format.
ACEContent.get\_axilent\_content\_type
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Returns the name of the ACE Content Type for the model.
ACEContent.sync\_with\_axilent
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Forces the local model to update from content from ACE. If there is no
corresponding content item in the ACE account, this method will do
nothing.
ACEContent.to\_content\_dict
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Returns content values as a dictionary according to the ``field_map``.
ACEContent.push\_to\_library
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Pushes the local values of the content into the associated ACE library.
This method returns a 2-tuple of booleans, indicating 1. if the library
was updated and 2. if a new content item was created in the library.
ACEContent.push\_to\_graphstack
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Puhes the local values of the content directly into the associated
GraphStack. A GraphStack in ACE is a logical container for deployed or
published content.
ACEContent.archive
^^^^^^^^^^^^^^^^^^
Removes the content from any GraphStack where it has been deployed.
ACEContent.live\_delete
^^^^^^^^^^^^^^^^^^^^^^^
Removes the associated ACE content item from the active GraphStack where
it is deployed.
ACEContent.tag
^^^^^^^^^^^^^^
Tags the content item within the associated ACE library.
ACEContent.detag
^^^^^^^^^^^^^^^^
De-tags the content item within the associated ACE library.
ACEContent.live\_tag
^^^^^^^^^^^^^^^^^^^^
Tags the content item where it has been deployed in the associated
GraphStack.
ACEContent.live\_detag
^^^^^^^^^^^^^^^^^^^^^^
De-tags the content item where it has been deployed in the associated
GraphStack.
ACEContent.reindex\_search
^^^^^^^^^^^^^^^^^^^^^^^^^^
Forces search re-indexing of the deployed associated content.
ACEContent.trigger\_affinity
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sends an affinity trigger for this content to ACE.
ACEContent.trigger\_ban
^^^^^^^^^^^^^^^^^^^^^^^
Sends a ban trigger for this content to ACE.
Setting Up Djax and ACE to Handle User-Generated Content
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A common scenario is User Generated Content (UGC), in which user's of
the website create content, in the form of Django models, which then
needs to be pushed back into the ACE library for administrative review.
Djax and ACE now support this round-trip model for content.
In the ACE project, first create a new **Content Source** for the
Content Type that you want to round-trip. Content Sources are found in
the settings panel, for each content type under the Content Types
section of the ACE project.
The new Content Source should be of the type **Djax User Generated
Content**. When creating the Content Source, you will need to set the
refresh interval, the URL pointing to the Djax install, and an auth
token.
In your code, you set up your model as ``ACEContent`` as usual, defining
the ACE content type and the field map in the ``ACE`` subclass.
Everytime the Content Source passes the refresh interval, it will query
your Djax install. At this point the Djax install will push the content
into the ACE library, either creating new content items or updating
existing ones.

%prep
%autosetup -n Djax-0.8.6

%build
%py3_build

%install
%py3_install
install -d -m755 %{buildroot}/%{_pkgdocdir}
if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
pushd %{buildroot}
if [ -d usr/lib ]; then
	find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
fi
if [ -d usr/lib64 ]; then
	find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
fi
if [ -d usr/bin ]; then
	find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
fi
if [ -d usr/sbin ]; then
	find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
fi
touch doclist.lst
if [ -d usr/share/man ]; then
	find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
fi
popd
mv %{buildroot}/filelist.lst .
mv %{buildroot}/doclist.lst .

%files -n python3-Djax -f filelist.lst
%dir %{python3_sitelib}/*

%files help -f doclist.lst
%{_docdir}/*

%changelog
* Thu May 18 2023 Python_Bot <Python_Bot@openeuler.org> - 0.8.6-1
- Package Spec generated