Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model customisations are not picked up #313

Open
AliIslamov opened this issue Nov 12, 2023 · 1 comment
Open

Model customisations are not picked up #313

AliIslamov opened this issue Nov 12, 2023 · 1 comment

Comments

@AliIslamov
Copy link

AliIslamov commented Nov 12, 2023

I'm trying to override Topic.save method for forum_conversation model.

My goal is correct transliteration of Cyrillic into slug.

For this I did the following:

  1. Created apps folder in root.

  2. Created

apps/__init__.py

and

apps/forum_conversation/__init__.py
  1. Create apps/forum_conversation/admin.py :
from machina.apps.forum_conversation.apps import ForumConversationAppConfig as BaseForumConversationAppConfig

class ForumConversationAppConfig(BaseForumConversationAppConfig):

    name = 'apps.forum_conversation'
    default = True

from machina.apps.forum.admin import *
  1. Create apps/forum_conversation/model.py :
from django.db import models
from machina.apps.forum_conversation.abstract_models import AbstractTopic
from unidecode import unidecode
from pytils.translit import slugify


class Topic(AbstractTopic):
  
    def save(self, *args, **kwargs):

        """ Saves the topic instance. """

        # It is vital to track the changes of the forum associated with a topic in order to
        # maintain counters up-to-date.

        old_instance = None
        if self.pk:
            old_instance = self.__class__._default_manager.get(pk=self.pk)

        # Update the slug field
        self.slug = slugify(unidecode(self.subject))

        # Do the save
        super().save(*args, **kwargs)

        # If any change has been made to the parent forum, trigger the update of the counters
        if old_instance and old_instance.forum != self.forum:
            self.update_trackers()
            # The previous parent forum counters should also be updated
            if old_instance.forum:
                old_forum = old_instance.forum
                old_forum.refresh_from_db()
                old_forum.update_trackers()
                
                
from machina.apps.forum_conversation.models import *
  1. Commented line:
 #'machina.apps.forum_conversation',

And have wrote in settings.py :

'apps.forum_conversation',

As a result, while creating forum topic slug still consists of Cyrillic alphabet. Its look like model customisations are not picked up.

In Oscar docs I see:

In your overriding models.py, ensure that you import Oscar’s models after your custom ones have been defined. If that doesn’t help, you have an import from oscar.apps.*.models somewhere that is being executed before your models are parsed. One trick for finding that import: put assert False in the relevant Oscar’s models.py, and the stack trace will show you the importing module.

So I wrote line assert False in original forum_conversation/abstract_models.py :

class AbstractTopic(models.Model):

    def save(self, *args, **kwargs):
        assert False
        ...

And see while creating new topic this traceback:

Exception Location:	/var/www/******/data/www/*******/.venv/lib/python3.11/site-packages/machina/apps/forum_conversation/abstract_models.py, line 165, in save
Raised during:	machina.apps.forum_conversation.views.TopicCreateView

So, I conclude that it is also necessary to override class TopicCreateView for forum_conversation/views.py :

class TopicCreateView(PermissionRequiredMixin, TopicFormView):
    """ Allows users to create forum topics. """

    model = Topic
    permission_required = ['can_start_new_topics', ]
    template_name = 'forum_conversation/topic_create.html'

    def get(self, request, *args, **kwargs):
        """ Handles GET requests. """
        self.object = None
        return super().get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        """ Handles POST requests. """
        self.object = None
        return super().post(request, *args, **kwargs)

    def get_controlled_object(self):
        """ Returns the controlled object. """
        return self.get_forum()

    def get_success_url(self):
        """ Returns the URL to redirect the user to upon valid form processing. """
        if not self.forum_post.approved:
            return reverse(
                'forum:forum',
                kwargs={
                    'slug': self.forum_post.topic.forum.slug,
                    'pk': self.forum_post.topic.forum.pk,
                },
            )
        return reverse(
            'forum_conversation:topic',
            kwargs={
                'forum_slug': self.forum_post.topic.forum.slug,
                'forum_pk': self.forum_post.topic.forum.pk,
                'slug': self.forum_post.topic.slug,
                'pk': self.forum_post.topic.pk,
            },
        )

But I can't understand what exactly do I need to change? 🤔

It is interesting that if I commended the whole method def save in original forum_conversation/abstract_models.py then everything works well and I get correct transliteration in topic slug.

@ellmetha
Copy link
Owner

Hey! 👋 No need to override the TopicCreateView view to perform what you are trying to do. Unfortunately what you are trying to do (ie. change the implementation of the save() method of the Topic model) may not be possible in an elegant way: the default save() implementation still comes from the AbstractTopic class, and since your method is setting the slug and then calling super().save(), then the default implementation essentially overrides your slug value.

If you absolutely want this to work you could do something like this:

class Topic(AbstractTopic):
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        self.slug = slugify(unidecode(self.subject))
        self._simple_save()

Where you essentially call the default save() implementation, then set your intended slug value and then do another save. But it means two saves performed at the DB level.

The best way forward would be to make it easier to customize how the slug is generated in the library (eg. by extracting the slug assignment into a dedicated method in AbstractTopic so that it can be easily replaced).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants