{"id":18438686,"url":"https://github.com/seapagan/pyblog","last_synced_at":"2025-07-19T16:35:43.461Z","repository":{"id":38188576,"uuid":"404267611","full_name":"seapagan/pyBlog","owner":"seapagan","description":"Django-based Blog engine with Comments, Tags, Likes, Pinned Posts, WYSIWYG Editing and more. Fully Responsive. Still Work in progress","archived":false,"fork":false,"pushed_at":"2024-05-27T19:08:36.000Z","size":2021,"stargazers_count":2,"open_issues_count":22,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-05-28T01:56:44.957Z","etag":null,"topics":["blog","django","django-authentication","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/seapagan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-08T08:21:07.000Z","updated_at":"2024-05-29T21:33:56.893Z","dependencies_parsed_at":"2023-10-03T05:30:38.546Z","dependency_job_id":"d31d81e2-9cf9-4acb-9c08-c827e6a55964","html_url":"https://github.com/seapagan/pyBlog","commit_stats":null,"previous_names":["seapagan/myblog"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seapagan%2FpyBlog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seapagan%2FpyBlog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seapagan%2FpyBlog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seapagan%2FpyBlog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seapagan","download_url":"https://codeload.github.com/seapagan/pyBlog/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245841761,"owners_count":20681195,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blog","django","django-authentication","python"],"created_at":"2024-11-06T06:21:08.303Z","updated_at":"2025-03-27T12:17:12.784Z","avatar_url":"https://github.com/seapagan.png","language":"Python","readme":"# pyBlog : A Django-based Blogging engine \u003c!-- omit in toc --\u003e\n\nThis application is a work in progress to write a blogging Engine in Django for\nmy personal use, and release as OSS when it reaches that level.\n\nThis README is very basic and will be updated as I add more functionality to the\nproject.\n\n- [Progress](#progress)\n  - [Already Implemented](#already-implemented)\n  - [Minimum required before Release](#minimum-required-before-release)\n  - [Good to Have](#good-to-have)\n- [Installation and Usage](#installation-and-usage)\n  - [Install the dependencies](#install-the-dependencies)\n    - [Using the `requirements.txt` file](#using-the-requirementstxt-file)\n  - [Register for Google Recaptcha](#register-for-google-recaptcha)\n  - [Optionally add Google Analytics](#optionally-add-google-analytics)\n  - [Set up the .env file](#set-up-the-env-file)\n  - [Migrate the Database](#migrate-the-database)\n  - [Create a Superuser](#create-a-superuser)\n  - [Download GeoIP data if required](#download-geoip-data-if-required)\n  - [Run the Development server](#run-the-development-server)\n  - [Maintenance mode](#maintenance-mode)\n  - [Running behind a Proxy](#running-behind-a-proxy)\n\n## Progress\n\n### Already Implemented\n\n- Users can login/logout/register etc. Registered users cannot post, though they\n  can be elevated to Author status by a Superuser. This allows 'Guest Poster'\n  functionality. All registered users can comment. Anonymous users can also\n  comment though they need to supply a username (and soon email) and\n  cannot edit a comment once submitted.\n- Users with a registered Gravatar have this automatically used for their\n  profile picture, but can also specify another.\n- Ability to Post (limited to Superuser and users with the Author flag set as\n  true)\n- Comment on a Post\n- Tag posts with similar topics, list all the tags, and list posts for each tag.\n- A post can be set as 'draft' and published later. Draft posts are hidden from\n  all but a Superuser or the post author.\n- Ability to 'like' a post, with a single vote per logged or anonymous user.\n  Page views are tracked (anonymously and only used for internal page ranking).\n  Like button uses Ajax, so it does not force a page refresh.\n- Responsive design - Sidebar on larger screens and degrading cleanly to a\n  drop-down menu on smaller. The menu is CSS only.\n- Sidebar has a section for 6 most 'Popular Posts' (ranked by page views then\n  user likes) and 'Recent Posts' showing the 6 latest.\n- Full WYSIWYG editor for both Posts and Comments, the author can add links,\n  pictures, emojis, etc. We cannot add images to comments, however\n- Profile page for each registered user, showing their Posts, Comments and\n  Social Media links.\n- Posts can have an image assigned to them; this appears on the main page\n  summary and each post detail page. If the image is not specified, we show a\n  default.\n- Pagination of posts and Comments\n- Ability to 'Pin' a single post at the top of the first page to give it\n  exposure.\n- Post URLs use a 'slug' created from the post title, helping with SEO.\n- URLs are protected by Authentication/Authorization and custom 403/404 views\n  have been implemented.\n- Site maintenance functionality - the whole site is blocked with an informative\n  page when enabled, except for logged in 'Staff' user or above.\n- Site preferences module is integrated, which sets the site Name, Tagline,\n  Pinned post and more through the Database. This allows very easy customization\n  without needing to change the code. All styling is through CSS classes, so\n  it is easy to change the look.\n- Sensitive variables (Secret, database credentials, etc) are taken from ENV\n  variables or `.env` file if it exists\n- Post search functionality - currently only searches by post Title and\n  Description.\n- ReCaptcha to help protect the Login, Registration, and comment functionality\n  from abuse.\n- Google Search sitemap generated on request at `/sitemap.xml`.\n- RSS feed available for Blog Posts at `/feed/posts/`. I will probably add a\n  comments feed or upgrade this feed to list comments also.\n- Local HTML, CSS and JS are minimized on the fly in production mode, left as-is\n  in DEBUG mode.\n- Add the metadata for Twitter Cards.\n- Display image metadata for the main title image\n- Add a `Google Analytics` tag if required\n\n### Minimum required before Release\n\n- Add proper Testing.\n- Add Timezone support, so the user sees all times in his local timezone.\n- Disable Django's admin in Production mode - (completely - the admin app and\n  URLs are not even loaded). `This is already done`, though I may want to add\n  the ability for specific trusted IPs to still access the admin if needed.\n- Tidy up the CSS, probably refactor to SCSS\n\n### Good to Have\n\n- Dedicated Admin site for superusers and potentially an 'admin' user (who can\n  only access Blog admin, not the Django admin site.)\n- Add 'Series' functionality where a set of posts can be grouped numerically and\n  accessed as such.\n- API to allow this backend to be used by totally separate frontend, Token Auth\n  where needed.\n- Add a list of other recommended posts at the bottom of each post, calculated\n  on post tags and popularity.\n- Add a future post mode. Can use the background module to daily check for any\n  future published posts and publish them.\n- Two-factor Authentication. Optional for normal users, compulsory for Staff,\n  Authors and Superuser.\n\nSee the [TODO.md](TODO.md) at the root of this repository for full details of\noutstanding bugs and plans.\n\n## Installation and Usage\n\nFrom the root of the checked-out repository:\n\n### Install the dependencies\n\nI have switched over to using [uv](https://docs.astral.sh/uv/) to have much\nbetter control of Dependencies. Please make sure that it is installed globally\nbefore continuing.\n\n```terminal\nuv sync\nsource .venv/bin/activate\n```\n\nThis will install all the dependencies and switch to a virtual environment ready\nto use the app.\n\n#### Using the `requirements.txt` file\n\nIf you prefer to use the `requirements.txt` file, or cannot use `uv` for some\nreason, you can install the dependencies using `pip`:\n\n```bash\npip install -r requirements.txt\n```\n\nThis will install all the required packages for the application. This may be\nrequired for hosting services that do not support `uv` or similar.\n\nIf you are developing, you may want to install the `dev-requirements.txt` file\ninstead.\n\n```bash\npip install -r requirements-dev.txt\n```\n\n\u003e [!NOTE]\n\u003e\n\u003e The above 2 commands are ONLY required if you are NOT using `uv` to manage the\n\u003e dependencies.\n\u003e\n\u003e Both the `requirements.txt` and `requirements-dev.txt` files are generated by\n\u003e the pre-commit hooks, so they should always be up to date with the current\n\u003e dependencies.\n\n### Register for Google Recaptcha\n\nThe Comment system is protected using a `Recaptcha` to help avoid bots.\n\nVisit the [Google Recaptcha][recaptcha] site, register if not already done, then\nset up a site for this Blog. Copy the public and private keys; you need to\nadd them to the `.env` file below. Choose the `V2 Tickbox type` as that is\nwhat we use for this application (at the moment, however, this hard-coded\nsetting will likely be removed later to allow all types).\n\n### Optionally add Google Analytics\n\nYou can add Google Analytics by adding your own personal site key to the `.env`\nfile :\n\n```ini\nGOOGLE_ANALYTICS_ENABLED=1 # 0 is disabled (default), 1 is enabled\nGOOGLE_ANALYTICS_TAG='UA-1234567-1' #Use your own key\n```\n\n### Set up the .env file\n\nWe keep some of the more secret settings in a .env file which does not go into\nsource control. There is a file `.env.example` in the project root - rename this\nto `.env` and set the values as you need. First, you want to generate\na new SECRET_KEY and set up the database login details :\n\n```ini\n# set our secret key. Go to https://djecrety.ir/ to generate a good one\nSECRET_KEY=\"this_is_not_very_secret\"\n\n# set up Database Users. We are using Postgresql, and this should already\n# exist with the correct user and password\nBLOG_DB_USER=\nBLOG_DB_PASSWORD=\nBLOG_DB_NAME=\nBLOG_DB_HOST=\nBLOG_DB_PORT=\n\n# Extra hosts for ALLOWED_HOSTS, generally the same as your domain name / IP\n# this should be a string of comma-separated values, e.g.:\n# ALLOWED_HOSTS=\"www.example.com,www.example.net\"\nALLOWED_HOSTS=\"\"\n\n# setup ReCaptcha keys - SET THESE TO YOUR OWN KEYS FROM ABOVE\nRECAPTCHA_PUBLIC_KEY=\"my_public_key\"\nRECAPTCHA_PRIVATE_KEY=\"my_private_key\"\n\n# Google analytics key - CHANGE TO YOUR OWN SITE-SPECIFIC KEY\n# This functionality is not currently working!\nGOOGLE_ANALYTICS_ENABLED=1\nGOOGLE_ANALYTICS_TAG='UA-1234567-1'\n```\n\nIn Production, If you are self-hosting your app and the server is secure, you\ncan keep the .env file, and it will be used in Production. However, with\nservices that support ENV variables (eg Heroku, Netlify, and more), it is better\nto define the variables in their dedicated interfaces. Also, make sure that the\n.env file CANNOT be loaded using a web browser! It is possible to use the AWS\n'Parameter Store', GCS 'Secret Manager', Hashicorp 'Vault' or others for your\nproduction env.\n\n### Migrate the Database\n\nYou need to adjust the database settings to your own needs; we use Postgresql as\nthe Database backend.\n\n```bash\npython manage.py migrate\n```\n\n### Create a Superuser\n\nThe Superuser automatically has Author rights, which regular users\nregistered to the app will not, so we need at least one. The Django default\nadmin site is completely removed in a non-DEBUG setting.\n\n```bash\npython manage.py createsuperuser\n```\n\n### Download GeoIP data if required\n\nThe sessions package can list the GeoIP data of your logged-in users; however,\nit needs you to download a couple of files that we cannot redistribute. See\n[This website][geo_data] for details. These 2 `.mmdb` files should be put in the\n`/geoip` directory of this repository. Without them, the sessions will not\nreturn location data.\n\nThis option may also be used for later (anonymous) visitor profiling, nothing\nplanned yet.\n\n### Run the Development server\n\nThe application defaults to **Production** mode unless the `DEBUG` variable is\nset to 1 (you can also set this in the .env file)\n\n```bash\nDEBUG=1 python manage.py runserver\n```\n\nYou can now access the application in your browser at `http://localhost:8000`\n\n### Maintenance mode\n\nThe entire site can be locked down, returning a `503 Service Unavailable` error\nfor all anonymous users or registered users below the 'Staff' level. Locking\ncan be done by the **Superuser only** from the sidebar or menu. It can also be\ndone from the local terminal in the Django project directory using the below\nmanagement commands :\n\n```bash\npython manage.py maintenance_mode \u003con|off\u003e\n```\n\nDuring Maintenance mode, a banner is shown at the top of the screen to remind\nany logged in users that the site is unavailable to the public.\n\n### Running behind a Proxy\n\nIf you are running the site behind an HTTP proxy (`Nginx`, for example), it is\npossible the Geo-location will not work, as the IP address will be blank or\nwrong. We need to modify the `REMOTE_ADDR` HTTP header to use the address from\n`HTTP_X_FORWARDED_FOR`. There is a middleware installed in the application to do\nthis, but we disable this by default. Try without first (this is a security risk\nUNLESS you are running behind a proxy you control), but if your sessions cannot\nget the IP, or Geo-location does not work, change the `FIX_PROXY_IP` in `.env`\nto be 1; by default, it is False (0):\n\n```python\n# Set to 1 IF NEEDED AND BEHIND A PROXY. See README.\nFIX_PROXY_IP=0\n```\n\n[geo_data]: https://dev.maxmind.com/geoip/geolite2-free-geolocation-data\n[recaptcha]: https://www.google.com/recaptcha/about/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseapagan%2Fpyblog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseapagan%2Fpyblog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseapagan%2Fpyblog/lists"}