forked from rc/aircox
		
	logo; RelatedPost sync with related object
This commit is contained in:
		@ -92,15 +92,15 @@ class RelatedPostBase (models.base.ModelBase):
 | 
			
		||||
    registry = {}
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def register (cl, key, model):
 | 
			
		||||
    def register (cl, key, post_model):
 | 
			
		||||
        """
 | 
			
		||||
        Register a model and return the key under which it is registered.
 | 
			
		||||
        Raise a ValueError if another model is yet associated under this key.
 | 
			
		||||
        """
 | 
			
		||||
        if key in cl.registry and cl.registry[key] is not model:
 | 
			
		||||
        if key in cl.registry and cl.registry[key] is not post_model:
 | 
			
		||||
            raise ValueError('A model has yet been registered with "{}"'
 | 
			
		||||
                             .format(key))
 | 
			
		||||
        cl.registry[key] = model
 | 
			
		||||
        cl.registry[key] = post_model
 | 
			
		||||
        return key
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
@ -137,13 +137,15 @@ class RelatedPostBase (models.base.ModelBase):
 | 
			
		||||
        return rel
 | 
			
		||||
 | 
			
		||||
    def __new__ (cl, name, bases, attrs):
 | 
			
		||||
        # TODO: allow proxy models and better inheritance
 | 
			
		||||
        if name == 'RelatedPost':
 | 
			
		||||
            return super().__new__(cl, name, bases, attrs)
 | 
			
		||||
 | 
			
		||||
        rel = cl.make_relation(name, attrs)
 | 
			
		||||
        field_args = rel.field_args or {}
 | 
			
		||||
        attrs['_relation'] = rel
 | 
			
		||||
        attrs.update({ x:y for x,y in {
 | 
			
		||||
            'related': models.ForeignKey(rel.model),
 | 
			
		||||
            'related': models.ForeignKey(rel.model, **field_args),
 | 
			
		||||
            '__str__': lambda self: str(self.related)
 | 
			
		||||
        }.items() if not attrs.get(x) })
 | 
			
		||||
 | 
			
		||||
@ -207,6 +209,8 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
			
		||||
        * rel_to_post: auto update the post when related object is updated
 | 
			
		||||
        * thread_model: generated by the metaclass, points to the RelatedPost
 | 
			
		||||
            model generated for the bindings.thread object.
 | 
			
		||||
        * field_args: dict of arguments to pass to the ForeignKey constructor,
 | 
			
		||||
            such as: ForeignKey(related_model, **field_args)
 | 
			
		||||
 | 
			
		||||
        Be careful with post_to_rel!
 | 
			
		||||
        * There is no check of permissions when related object is synchronised
 | 
			
		||||
@ -217,14 +221,15 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
			
		||||
        model = None
 | 
			
		||||
        bindings = None          # values to map { post_attr: rel_attr }
 | 
			
		||||
        post_to_rel = False
 | 
			
		||||
        rel_to_post = True
 | 
			
		||||
        rel_to_post = False
 | 
			
		||||
        thread_model = None
 | 
			
		||||
        field_args = None
 | 
			
		||||
 | 
			
		||||
    def get_rel_attr(self, attr):
 | 
			
		||||
        attr = self._relation.bindings.get(attr)
 | 
			
		||||
        return getattr(self.related, attr) if attr else None
 | 
			
		||||
 | 
			
		||||
    def set_rel_attr(self, attr, value)
 | 
			
		||||
    def set_rel_attr(self, attr, value):
 | 
			
		||||
        if attr not in self._relation.bindings:
 | 
			
		||||
            raise AttributeError('attribute {} is not bound'.format(attr))
 | 
			
		||||
        attr = self._relation.bindings.get(attr)
 | 
			
		||||
@ -240,13 +245,13 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
			
		||||
        if not rel.bindings:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        for attr, rel_attr in rel.bindings.items()
 | 
			
		||||
        for attr, rel_attr in rel.bindings.items():
 | 
			
		||||
            if attr == 'thread':
 | 
			
		||||
                continue
 | 
			
		||||
            value = getattr(self, attr) if hasattr(self, attr) else None
 | 
			
		||||
            setattr(self.related, rel_attr, value)
 | 
			
		||||
 | 
			
		||||
        if self.thread_model:
 | 
			
		||||
        if rel.thread_model:
 | 
			
		||||
            thread = self.thread if not issubclass(thread, rel.thread_model) \
 | 
			
		||||
                        else None
 | 
			
		||||
            self.set_rel_attr('thread', thread.related)
 | 
			
		||||
@ -254,6 +259,19 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
			
		||||
        if save:
 | 
			
		||||
            self.related.save()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def sync_from_rel(cl, rel, save = True):
 | 
			
		||||
        """
 | 
			
		||||
        Update a rel_to_post from a given rel object. Return -1 if there is no
 | 
			
		||||
        related post to update
 | 
			
		||||
        """
 | 
			
		||||
        self = cl.objects.filter(related = rel)
 | 
			
		||||
        if not self or not self.count():
 | 
			
		||||
            return -1
 | 
			
		||||
        self[0].rel_to_post(save)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def rel_to_post(self, save = True):
 | 
			
		||||
        """
 | 
			
		||||
        Change the post using the related object bound values. Save the
 | 
			
		||||
@ -264,7 +282,7 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
			
		||||
        if rel.bindings:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        for attr, rel_attr in rel.bindings.items()
 | 
			
		||||
        for attr, rel_attr in rel.bindings.items():
 | 
			
		||||
            if attr == 'thread':
 | 
			
		||||
                continue
 | 
			
		||||
            self.set_rel_attr
 | 
			
		||||
@ -272,7 +290,7 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
			
		||||
                    if hasattr(self.related, attr) else None
 | 
			
		||||
            setattr(self, attr, value)
 | 
			
		||||
 | 
			
		||||
        if self.thread_model:
 | 
			
		||||
        if rel.thread_model:
 | 
			
		||||
            thread = self.get_rel_attr('thread')
 | 
			
		||||
            thread = rel.thread_model.objects.filter(related = thread) \
 | 
			
		||||
                        if thread else None
 | 
			
		||||
@ -282,11 +300,19 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
			
		||||
        if save:
 | 
			
		||||
            self.save()
 | 
			
		||||
 | 
			
		||||
    def __init__ (self, *kargs, **kwargs):
 | 
			
		||||
        super().__init__(*kargs, **kwargs)
 | 
			
		||||
        # we use this method for sync, in order to avoid intrusive code on other
 | 
			
		||||
        # applications, e.g. using signals.
 | 
			
		||||
        if self._relation.rel_to_post:
 | 
			
		||||
            self.rel_to_post(save = False)
 | 
			
		||||
 | 
			
		||||
    def save (self, *args, **kwargs):
 | 
			
		||||
        # TODO handle when related change
 | 
			
		||||
        if not self.title and self.related:
 | 
			
		||||
            self.title = self.get_rel_attr('title')
 | 
			
		||||
        if self._relation.post_to_rel:
 | 
			
		||||
            self.post_to_rel(False)
 | 
			
		||||
            self.post_to_rel(save = True)
 | 
			
		||||
        super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@
 | 
			
		||||
        <meta name="description" content="{{ website.description }}">
 | 
			
		||||
        <meta name="keywords" content="{{ website.tags }}">
 | 
			
		||||
 | 
			
		||||
        <link rel="stylesheet" href="{% static "aircox_cms/styles.css" %}" type="text/css">
 | 
			
		||||
        <link rel="stylesheet" href="{% static "aircox/cms/styles.css" %}" type="text/css">
 | 
			
		||||
        {% if website.styles %}
 | 
			
		||||
        <link rel="stylesheet" href="{% static website.styles %}" type="text/css">
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
{% extends embed|yesno:"aircox_cms/base_content.html,aircox_cms/base_site.html" %}
 | 
			
		||||
{% extends embed|yesno:"aircox/cms/base_content.html,aircox/cms/base_site.html" %}
 | 
			
		||||
 | 
			
		||||
{% block title %}
 | 
			
		||||
{{ object.title }}
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
{% extends embed|yesno:"aircox_cms/base_content.html,aircox_cms/base_site.html" %}
 | 
			
		||||
{% extends embed|yesno:"aircox/cms/base_content.html,aircox/cms/base_site.html" %}
 | 
			
		||||
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
{% load thumbnail %}
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
{% extends "aircox_cms/base_section.html" %}
 | 
			
		||||
{% extends "aircox/cms/base_section.html" %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% if title %}
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
{% extends "aircox_cms/section.html" %}
 | 
			
		||||
{% extends "aircox/cms/section.html" %}
 | 
			
		||||
 | 
			
		||||
{% load thumbnail %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -307,6 +307,8 @@ class Sections:
 | 
			
		||||
        """
 | 
			
		||||
        @property
 | 
			
		||||
        def content (self):
 | 
			
		||||
            if not self.object.image:
 | 
			
		||||
                return ''
 | 
			
		||||
            return '<img src="{}" class="post_image">'.format(
 | 
			
		||||
                        self.object.image.url
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user