diff options
| author | CoprDistGit <infra@openeuler.org> | 2023-05-18 06:21:10 +0000 |
|---|---|---|
| committer | CoprDistGit <infra@openeuler.org> | 2023-05-18 06:21:10 +0000 |
| commit | baa4dcfa56c4757d004cead8663682fa7ac5b327 (patch) | |
| tree | a204002aac0a59cdf3898bd54c1c386488988ba0 | |
| parent | ef32651ee288ddae6e584e897152e7b4be35f551 (diff) | |
automatic import of python-djax
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | python-djax.spec | 870 | ||||
| -rw-r--r-- | sources | 1 |
3 files changed, 872 insertions, 0 deletions
@@ -0,0 +1 @@ +/Djax-0.8.6.tar.gz diff --git a/python-djax.spec b/python-djax.spec new file mode 100644 index 0000000..22730d0 --- /dev/null +++ b/python-djax.spec @@ -0,0 +1,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 @@ -0,0 +1 @@ +614fbcf62cd4b08b651b90f4058aa3fc Djax-0.8.6.tar.gz |
