How to add and change an app from github

Hi all,

thanks to all of the great documentation I’m really making some progress. Now another question appeared. This might be pretty obvious for someone who is using object orientation regulary, but unluckily I’m still new to the practical application of some python concepts.

Question:
How do I modify a django application that I implemented into my project?

Example:
I’m using the post_office app in my project and would like to

  • modify some code in two mail.py functions
  • add a few new fields in the Email model of post_office

What did I do?

  • pip install django-post_office
  • python manage.py migrate

My plan

  1. Copy / paste the whole mail.py file into the app I’m just programming, due to the fact that it’s not object oriented, so I’m not able to built a class instance. Then make the changes inside my copied file.

  2. Create an instance of the model and hope / make sure, that my model still works with the other models from the post_office app, e.g. the Logs model.

Is is really that easy or do I miss anything here?

This is one of those topics for which there isn’t a fixed or firm answer. The only response I can make is “it depends”. Mostly, it depends upon specifically what the changes are you’re looking to make and what the level of integration is between the app and your code.

For example, if you need to just add two fields to the Email model, you could create this extension using multi-table inheritance. The existing functions aren’t going to be aware of those fields, but then you wouldn’t expect them to.

Use Multi-table inheritance they said. It will be easy, they said… :roll_eyes: :rofl: :rofl: :rofl:

Thanks again Ken! (By the way: I just heared your great interview on the django chat podcast… :slight_smile:)

Issue:
Clicking the following link, post_office allows to add an e-mail in another language.

When pushed, it looks like that:

I created a class Instance of post_office’s EmailTemplate model:

class NewEmailTemplate(pmodels.EmailTemplate):
    foo = models.CharField(_("Foo"), max_length=254)

But after registering the model in my app’s admin.py…

admin.site.register(models.NewEmailTemplate)

…it does not work as intended. Instead of being able to create the same e-mail again in another language, I have to choose an entry the original post_office.model.EmailTemplate app:

A quick look into the post_office.models file shows, that there is a field called “default_template” which is used to add an e-mail in another language. It contains recursion / the value ‘self’.

default_template = models.ForeignKey('self', related_name='translated_templates',
        null=True, default=None, verbose_name=_('Default template'), on_delete=models.CASCADE)

What I tried out:

  • Trying to overwrite the field obviously did not help. Exception:
django.core.exceptions.FieldError: Local field 'default_template' in class 'NewEmailTemplate' clashes with field of the same name from base class 'EmailTemplate'.
  • Trying to copy / paste the whole code of the model didn’t help either. Still the same field from the 3rd screenshot, instead of the possibility to create the same email in another language (but now it references to the ‘correct’ model).

So I’m a little bit confused what might be a good way to continue so it would be very appreciated if anyone has a good idea. :slight_smile:

So I’m having difficulty seeing in what you’ve posted, what exactly you’re trying to do here.

You’ve shown creating a new model with a new field. That’s going to create another table in your database with two fields. The CharField named “foo” and a ForeignKey to EmailTemplate. I would expect the admin to show you all the editable fields from both models if you access the new model in the admin. However, if you access the parent model, I wouldn’t expect it to provide any information about the child model.

Ignoring the implementation details for a moment - what is your objective you are trying to accomplish? (Not the technical details, the “Use case” or “business case”.)

Short description of the screenshots:

1st screenshot:
Shows the admin interface from the original “EmailTemplate” when adding a new EMail Template. Down below is a “+” with a link, saying “Add E-Mail template”. After pushing that…

2nd screenshot:
…another form opens below the EmailTemplate form, where I can add the same Email in another language.

3rd screenshot:
When I use the model via Multi-table inheritance, in the admin interface, instead of the “+ Add E-Mail template” I just see a “standard template” selection field, where I have to chose another e-mail which was saved as EmailTemplate before.

My use case:

  1. Users shall receive emails with exercises. There is a pool which includes those ‘exercise e-mails’, the EmailTemplate model. So I would like to add fields like “difficulty” or “topic” to it.

  2. The template shall be chosen when the e-mail is sent, not when the email is scheduled for being sent at a later time. Background: Post_office allows me to send scheduled e-mails. But due to the fact that my pool of exercise e-mails is growing over the time, I don’t want to choose the EmailTemplate during scheduling. I want to choose an appropriate EmailTemplate just before the email is sent. Therefore I think I need to add a method in the model and make slight changes in the mail.py file.

Clearly a case where multitable inheritance can work for you.

I’m not seeing how this relates to #1 - if it does.

I also wouldn’t try forcing the admin for doing this. I think this fits into the category of creating a view for that purpose. But I’m not familiar with this package so I don’t really understand what you’re envisioning as the “flow” of events.

How are you going to “inject” yourself into this sequence of “scheduled” emails? Example: You schedule an email to go out Monday morning. Are you expecting those emails to be “paused” until you select / approve them being sent? What happens if you’re not logged on Monday morning? Do the emails not get sent?

I really hope so. :slight_smile:

Sorry for confusing you

Periodically a deamon calls a script in management/commands/ which executes methods from the mail.py linked above. The scheduled mails are then sent.
The idea is to put a simple “if template and message of a mail scheduled for now == None” statement at the beginning of the sending-process where the mail is prepared. If the statement is true, a function is called that chooses a (lets call it for now) random template and adds it to the enail. After that, the email may be sent normally using post_office.

Just winging this, but my first (cursory) impression and reaction would be to change the daemon to call my script. My script would have the conditions you describe, and if appropriate, either send the email myself or send it through “post_office”. I’m not sure there’s a lot to be gained from trying to modify the behavior of the package’s function.

1 Like

Just tried some things out on a console level. You are right. I’m facing an issue from the admin interface here. Adding and sending a mail using the console works great using Multi-table inheritance. So creating a view for this should work fine. :slight_smile:

Makes perfect sense!

Tinkering in the script itself would have the advantage that only one db query needs to be send, so the process would look like this:

  1. Start mail.py from post_office
  2. mail.py makes a query, which mails should have been sent during the last run
  3. Push those mails into a custom function where a “random” template is chosen, before proceeding
  4. Mails are proceeded by post_office and sent

…but this would obviously also mean tinkering in the script.

So your idea would mean the following process for me:

  1. Start a personal script
  2. the personal script makes a query which mails should have been sent during the last run
  3. Work on those mails using a custom function where a “random” template is chosen
  4. After this function has run successfully, run the mail.py from post_office
  5. mail.py makes a query, which mails should have been sent during the last run
  6. Mails are proceeded by post_office and sent

Using two db queries might take a bit more performance due to the two db queries, but thinking of the advantage of not tinkering in the post_office file while per run of the script less than 10 mails will be sent on average, I would completely agree to your solution and say that this makes perfect sense.

…or perhaps I can sent the emails directly after having modified them. Will have to dig into the code for that.

Thanks a lot for your support again, Ken!