Initials
This commit is contained in:
4
.env.example
Normal file
4
.env.example
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Copy to .env and set values
|
||||||
|
DJANGO_SECRET_KEY=replace-me
|
||||||
|
DJANGO_DEBUG=False
|
||||||
|
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
|
||||||
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
db.sqlite3
|
||||||
|
/media/
|
||||||
|
/staticfiles/
|
||||||
|
.env
|
||||||
32
.idea/eventify_prod.iml
generated
Normal file
32
.idea/eventify_prod.iml
generated
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="django" name="Django">
|
||||||
|
<configuration>
|
||||||
|
<option name="rootFolder" value="$MODULE_DIR$" />
|
||||||
|
<option name="settingsModule" value="eventify/settings.py" />
|
||||||
|
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
|
||||||
|
<option name="environment" value="<map/>" />
|
||||||
|
<option name="doNotUseTestRunner" value="false" />
|
||||||
|
<option name="trackFilePattern" value="migrations" />
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="TemplatesService">
|
||||||
|
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||||
|
<option name="TEMPLATE_FOLDERS">
|
||||||
|
<list>
|
||||||
|
<option value="$MODULE_DIR$/templates" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="TestRunnerService">
|
||||||
|
<option name="projectConfiguration" value="Twisted Trial" />
|
||||||
|
<option name="PROJECT_TEST_RUNNER" value="Twisted Trial" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
28
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
28
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredPackages">
|
||||||
|
<value>
|
||||||
|
<list size="1">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="cx_oracle" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredErrors">
|
||||||
|
<list>
|
||||||
|
<option value="E722" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PyShadowingNamesInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||||
|
<option name="processCode" value="true" />
|
||||||
|
<option name="processLiterals" value="true" />
|
||||||
|
<option name="processComments" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (untitled1)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/eventify_prod.iml" filepath="$PROJECT_DIR$/.idea/eventify_prod.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
319
.idea/workspace.xml
generated
Normal file
319
.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="a0020f0b-7bf3-4cde-a27d-39657ebd0286" name="Default Changelist" comment="" />
|
||||||
|
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="FileEditorManager">
|
||||||
|
<leaf>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/accounts/models.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="260">
|
||||||
|
<caret line="13" lean-forward="true" selection-start-line="13" selection-end-line="13" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#51#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/templates/accounts/login.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-103" />
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/templates/accounts/user_form.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/templates/accounts/user_list.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/templates/accounts/user_confirm_delete.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="true">
|
||||||
|
<entry file="file://$PROJECT_DIR$/templates/base.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/master_data/models.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/master_data/views.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-183">
|
||||||
|
<caret line="6" column="47" lean-forward="true" selection-start-line="6" selection-start-column="47" selection-end-line="6" selection-end-column="47" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#32#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/eventify/settings.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-1463">
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#9#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file pinned="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/master_data/migrations/0001_initial.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
</leaf>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectFrameBounds" extendedState="6">
|
||||||
|
<option name="x" value="-85" />
|
||||||
|
<option name="y" value="14" />
|
||||||
|
<option name="width" value="1386" />
|
||||||
|
<option name="height" value="788" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectView">
|
||||||
|
<navigator proportions="" version="1">
|
||||||
|
<foldersAlwaysOnTop value="true" />
|
||||||
|
</navigator>
|
||||||
|
<panes>
|
||||||
|
<pane id="Scope" />
|
||||||
|
<pane id="ProjectPane">
|
||||||
|
<subPane>
|
||||||
|
<expand>
|
||||||
|
<path>
|
||||||
|
<item name="eventify_prod" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="eventify_prod" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="eventify_prod" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="eventify_prod" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="master_data" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<item name="eventify_prod" type="b2602c69:ProjectViewProjectNode" />
|
||||||
|
<item name="eventify_prod" type="462c0819:PsiDirectoryNode" />
|
||||||
|
<item name="templates" type="462c0819:PsiDirectoryNode" />
|
||||||
|
</path>
|
||||||
|
</expand>
|
||||||
|
<select />
|
||||||
|
</subPane>
|
||||||
|
</pane>
|
||||||
|
</panes>
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||||
|
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||||
|
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||||
|
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="RunDashboard">
|
||||||
|
<option name="ruleStates">
|
||||||
|
<list>
|
||||||
|
<RuleState>
|
||||||
|
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||||
|
</RuleState>
|
||||||
|
<RuleState>
|
||||||
|
<option name="name" value="StatusDashboardGroupingRule" />
|
||||||
|
</RuleState>
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="RunManager">
|
||||||
|
<configuration name="eventify_prod" type="Python.DjangoServer" factoryName="Django server">
|
||||||
|
<module name="eventify_prod" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="PARENT_ENVS" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
|
</envs>
|
||||||
|
<option name="SDK_HOME" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="" />
|
||||||
|
<option name="IS_MODULE_SDK" value="false" />
|
||||||
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<option name="launchJavascriptDebuger" value="false" />
|
||||||
|
<option name="port" value="8000" />
|
||||||
|
<option name="host" value="" />
|
||||||
|
<option name="additionalOptions" value="" />
|
||||||
|
<option name="browserUrl" value="" />
|
||||||
|
<option name="runTestServer" value="false" />
|
||||||
|
<option name="runNoReload" value="false" />
|
||||||
|
<option name="useCustomRunCommand" value="false" />
|
||||||
|
<option name="customRunCommand" value="" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
|
<component name="SvnConfiguration">
|
||||||
|
<configuration />
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="a0020f0b-7bf3-4cde-a27d-39657ebd0286" name="Default Changelist" comment="" />
|
||||||
|
<created>1764194364815</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1764194364815</updated>
|
||||||
|
<workItem from="1764194366807" duration="1596000" />
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TimeTrackingManager">
|
||||||
|
<option name="totallyTimeSpent" value="1596000" />
|
||||||
|
</component>
|
||||||
|
<component name="ToolWindowManager">
|
||||||
|
<frame x="-8" y="-8" width="1382" height="744" extended-state="7" />
|
||||||
|
<editor active="true" />
|
||||||
|
<layout>
|
||||||
|
<window_info id="Favorites" side_tool="true" />
|
||||||
|
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.24962178" />
|
||||||
|
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
||||||
|
<window_info anchor="bottom" id="Docker" show_stripe_button="false" />
|
||||||
|
<window_info anchor="bottom" id="Database Changes" />
|
||||||
|
<window_info anchor="bottom" id="Version Control" />
|
||||||
|
<window_info anchor="bottom" id="Python Console" />
|
||||||
|
<window_info anchor="bottom" id="Terminal" visible="true" weight="0.32840723" />
|
||||||
|
<window_info anchor="bottom" id="Event Log" side_tool="true" />
|
||||||
|
<window_info anchor="bottom" id="Message" order="0" />
|
||||||
|
<window_info anchor="bottom" id="Find" order="1" weight="0.32840723" />
|
||||||
|
<window_info anchor="bottom" id="Run" order="2" />
|
||||||
|
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
||||||
|
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
||||||
|
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||||
|
<window_info anchor="bottom" id="TODO" order="6" />
|
||||||
|
<window_info anchor="right" id="SciView" />
|
||||||
|
<window_info anchor="right" id="Database" />
|
||||||
|
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
|
||||||
|
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||||
|
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||||
|
</layout>
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="1" />
|
||||||
|
</component>
|
||||||
|
<component name="editorHistoryManager">
|
||||||
|
<entry file="file://$PROJECT_DIR$/accounts/views.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="660">
|
||||||
|
<caret line="33" column="25" selection-start-line="33" selection-start-column="25" selection-end-line="33" selection-end-column="25" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#35#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/events/views.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="197">
|
||||||
|
<caret line="16" column="51" selection-start-line="16" selection-start-column="51" selection-end-line="16" selection-end-column="51" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#32#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/.env.example">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/events/models.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state>
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#28#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/requirements.txt">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/.gitignore">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/README.md">
|
||||||
|
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
|
||||||
|
<state split_layout="SPLIT">
|
||||||
|
<first_editor relative-caret-position="-240" />
|
||||||
|
<second_editor />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://C:/Python38/Lib/site-packages/django/contrib/auth/models.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="247">
|
||||||
|
<caret line="354" column="5" selection-start-line="354" selection-start-column="5" selection-end-line="354" selection-end-column="5" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/eventify/settings.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-1463">
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#9#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/master_data/migrations/0001_initial.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/accounts/models.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="260">
|
||||||
|
<caret line="13" lean-forward="true" selection-start-line="13" selection-end-line="13" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#51#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/templates/accounts/login.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-103" />
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/templates/accounts/user_form.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/templates/accounts/user_list.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/templates/accounts/user_confirm_delete.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/master_data/models.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/master_data/views.py">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="-183">
|
||||||
|
<caret line="6" column="47" lean-forward="true" selection-start-line="6" selection-start-column="47" selection-end-line="6" selection-end-column="47" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#32#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/templates/base.html">
|
||||||
|
<provider selected="true" editor-type-id="text-editor" />
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
30
README.md
Normal file
30
README.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Eventify - Django
|
||||||
|
|
||||||
|
This repository contains a production-oriented Django project skeleton for the Eventify application.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Custom `User` model
|
||||||
|
- EventType (categories), Event, EventImages models
|
||||||
|
- CRUD for EventType, Event, and Users
|
||||||
|
- Bootstrap-based templates and navigation
|
||||||
|
- Settings prepared to use environment variables for production
|
||||||
|
|
||||||
|
## Quick start (development)
|
||||||
|
1. Create a virtualenv and activate it
|
||||||
|
```bash
|
||||||
|
python -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
2. Run migrations and create superuser
|
||||||
|
```bash
|
||||||
|
python manage.py migrate
|
||||||
|
python manage.py createsuperuser
|
||||||
|
python manage.py runserver
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production notes
|
||||||
|
- Set `DJANGO_SECRET_KEY`, `DJANGO_DEBUG`, and `DJANGO_ALLOWED_HOSTS` environment variables
|
||||||
|
- Collect static files with `python manage.py collectstatic`
|
||||||
|
- Serve via uWSGI/gunicorn + nginx or any WSGI server
|
||||||
|
|
||||||
10
accounts/admin.py
Normal file
10
accounts/admin.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
|
from .models import User
|
||||||
|
|
||||||
|
@admin.register(User)
|
||||||
|
class UserAdmin(BaseUserAdmin):
|
||||||
|
fieldsets = BaseUserAdmin.fieldsets + (
|
||||||
|
('Extra', {'fields':('phone_number','role','is_customer','is_user')}),
|
||||||
|
)
|
||||||
|
list_display = ('username','email','phone_number','role','is_staff')
|
||||||
12
accounts/forms.py
Normal file
12
accounts/forms.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.contrib.auth.forms import UserCreationForm
|
||||||
|
from .models import User
|
||||||
|
|
||||||
|
class UserForm(UserCreationForm):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ('username','email','phone_number','role','is_staff','is_customer','is_user')
|
||||||
|
|
||||||
|
from django.contrib.auth.forms import AuthenticationForm
|
||||||
|
class LoginForm(AuthenticationForm):
|
||||||
|
pass
|
||||||
48
accounts/migrations/0001_initial.py
Normal file
48
accounts/migrations/0001_initial.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2025-11-26 22:07
|
||||||
|
|
||||||
|
import django.contrib.auth.models
|
||||||
|
import django.contrib.auth.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('auth', '0012_alter_user_first_name_max_length'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='User',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||||
|
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||||
|
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||||
|
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||||
|
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||||
|
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||||
|
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
||||||
|
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||||
|
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||||
|
('phone_number', models.CharField(blank=True, max_length=15, null=True)),
|
||||||
|
('role', models.CharField(blank=True, max_length=50, null=True)),
|
||||||
|
('is_staff', models.BooleanField(default=False)),
|
||||||
|
('is_customer', models.BooleanField(default=False)),
|
||||||
|
('is_user', models.BooleanField(default=False)),
|
||||||
|
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||||
|
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'user',
|
||||||
|
'verbose_name_plural': 'users',
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
managers=[
|
||||||
|
('objects', django.contrib.auth.models.UserManager()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
0
accounts/migrations/__init__.py
Normal file
0
accounts/migrations/__init__.py
Normal file
13
accounts/models.py
Normal file
13
accounts/models.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from django.contrib.auth.models import AbstractUser
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class User(AbstractUser):
|
||||||
|
phone_number = models.CharField(max_length=15, blank=True, null=True)
|
||||||
|
role = models.CharField(max_length=50, blank=True, null=True)
|
||||||
|
|
||||||
|
is_staff = models.BooleanField(default=False)
|
||||||
|
is_customer = models.BooleanField(default=False)
|
||||||
|
is_user = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.username
|
||||||
11
accounts/urls.py
Normal file
11
accounts/urls.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'accounts'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('users/', views.UserListView.as_view(), name='user_list'),
|
||||||
|
path('users/add/', views.UserCreateView.as_view(), name='user_add'),
|
||||||
|
path('users/<int:pk>/edit/', views.UserUpdateView.as_view(), name='user_edit'),
|
||||||
|
path('users/<int:pk>/delete/', views.UserDeleteView.as_view(), name='user_delete'),
|
||||||
|
]
|
||||||
41
accounts/views.py
Normal file
41
accounts/views.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
from django.views import generic
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from .models import User
|
||||||
|
from .forms import UserForm
|
||||||
|
from events.models import Event
|
||||||
|
from master_data.models import EventType
|
||||||
|
|
||||||
|
def dashboard(request):
|
||||||
|
total_events = Event.objects.count()
|
||||||
|
total_categories = EventType.objects.count()
|
||||||
|
total_users = User.objects.count()
|
||||||
|
return render(request, 'dashboard.html', {
|
||||||
|
'total_events': total_events,
|
||||||
|
'total_categories': total_categories,
|
||||||
|
'total_users': total_users,
|
||||||
|
})
|
||||||
|
|
||||||
|
class UserListView(LoginRequiredMixin, generic.ListView):
|
||||||
|
model = User
|
||||||
|
template_name = 'accounts/user_list.html'
|
||||||
|
context_object_name = 'users'
|
||||||
|
paginate_by = 20
|
||||||
|
|
||||||
|
class UserCreateView(LoginRequiredMixin, generic.CreateView):
|
||||||
|
model = User
|
||||||
|
form_class = UserForm
|
||||||
|
template_name = 'accounts/user_form.html'
|
||||||
|
success_url = reverse_lazy('accounts:user_list')
|
||||||
|
|
||||||
|
class UserUpdateView(LoginRequiredMixin, generic.UpdateView):
|
||||||
|
model = User
|
||||||
|
form_class = UserForm
|
||||||
|
template_name = 'accounts/user_form.html'
|
||||||
|
success_url = reverse_lazy('accounts:user_list')
|
||||||
|
|
||||||
|
class UserDeleteView(LoginRequiredMixin, generic.DeleteView):
|
||||||
|
model = User
|
||||||
|
template_name = 'accounts/user_confirm_delete.html'
|
||||||
|
success_url = reverse_lazy('accounts:user_list')
|
||||||
0
eventify/__init__.py
Normal file
0
eventify/__init__.py
Normal file
4
eventify/asgi.py
Normal file
4
eventify/asgi.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import os
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eventify.settings')
|
||||||
|
application = get_asgi_application()
|
||||||
85
eventify/settings.py
Normal file
85
eventify/settings.py
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'change-me-in-production')
|
||||||
|
|
||||||
|
DEBUG = os.environ.get('DJANGO_DEBUG', 'False') == 'True'
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', '*').split(',')
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
'master_data',
|
||||||
|
'events',
|
||||||
|
'accounts',
|
||||||
|
]
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
]
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'eventify.urls'
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
|
'DIRS': [BASE_DIR / 'templates'],
|
||||||
|
'APP_DIRS': True,
|
||||||
|
'OPTIONS': {
|
||||||
|
'context_processors': [
|
||||||
|
'django.template.context_processors.debug',
|
||||||
|
'django.template.context_processors.request',
|
||||||
|
'django.contrib.auth.context_processors.auth',
|
||||||
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'eventify.wsgi.application'
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': BASE_DIR / 'db.sqlite3',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
|
||||||
|
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
|
||||||
|
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
|
||||||
|
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
|
||||||
|
]
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
TIME_ZONE = 'UTC'
|
||||||
|
USE_I18N = True
|
||||||
|
USE_L10N = True
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||||
|
STATICFILES_DIRS = [BASE_DIR / 'static']
|
||||||
|
|
||||||
|
MEDIA_URL = '/media/'
|
||||||
|
MEDIA_ROOT = BASE_DIR / 'media'
|
||||||
|
|
||||||
|
AUTH_USER_MODEL = 'accounts.User'
|
||||||
|
|
||||||
|
LOGIN_URL = 'login'
|
||||||
|
LOGIN_REDIRECT_URL = 'dashboard'
|
||||||
|
LOGOUT_REDIRECT_URL = 'login'
|
||||||
15
eventify/urls.py
Normal file
15
eventify/urls.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, include
|
||||||
|
from django.contrib.auth import views as auth_views
|
||||||
|
from accounts.views import dashboard
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('admin/', admin.site.urls),
|
||||||
|
path('', auth_views.LoginView.as_view(template_name='accounts/login.html'), name='login'),
|
||||||
|
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
|
||||||
|
path('dashboard/', dashboard, name='dashboard'),
|
||||||
|
|
||||||
|
path('master-data/', include('master_data.urls')),
|
||||||
|
path('events/', include('events.urls')),
|
||||||
|
path('accounts/', include('accounts.urls')),
|
||||||
|
]
|
||||||
4
eventify/wsgi.py
Normal file
4
eventify/wsgi.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import os
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eventify.settings')
|
||||||
|
application = get_wsgi_application()
|
||||||
12
events/admin.py
Normal file
12
events/admin.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from .models import Event, EventImages
|
||||||
|
|
||||||
|
@admin.register(Event)
|
||||||
|
class EventAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('id','name','start_date','end_date','event_type','event_status')
|
||||||
|
list_filter = ('event_status','event_type')
|
||||||
|
search_fields = ('name','place','district')
|
||||||
|
|
||||||
|
@admin.register(EventImages)
|
||||||
|
class EventImagesAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('id','event','is_primary')
|
||||||
11
events/forms.py
Normal file
11
events/forms.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from django import forms
|
||||||
|
from .models import Event
|
||||||
|
|
||||||
|
class EventForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Event
|
||||||
|
exclude = ['created_date']
|
||||||
|
widgets = {
|
||||||
|
'start_date': forms.DateInput(attrs={'type':'date'}),
|
||||||
|
'end_date': forms.DateInput(attrs={'type':'date'}),
|
||||||
|
}
|
||||||
48
events/migrations/0001_initial.py
Normal file
48
events/migrations/0001_initial.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2025-11-26 22:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('master_data', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Event',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_date', models.DateField(auto_now_add=True)),
|
||||||
|
('name', models.CharField(max_length=200)),
|
||||||
|
('description', models.TextField()),
|
||||||
|
('start_date', models.DateField()),
|
||||||
|
('end_date', models.DateField()),
|
||||||
|
('latitude', models.DecimalField(decimal_places=6, max_digits=9)),
|
||||||
|
('longitude', models.DecimalField(decimal_places=6, max_digits=9)),
|
||||||
|
('pincode', models.CharField(max_length=10)),
|
||||||
|
('district', models.CharField(max_length=100)),
|
||||||
|
('state', models.CharField(max_length=100)),
|
||||||
|
('place', models.CharField(max_length=200)),
|
||||||
|
('is_bookable', models.BooleanField(default=False)),
|
||||||
|
('is_eventify_event', models.BooleanField(default=True)),
|
||||||
|
('outside_event_url', models.URLField(default='NA')),
|
||||||
|
('event_status', models.CharField(choices=[('created', 'Created'), ('cancelled', 'Cancelled'), ('pending', 'Pending'), ('completed', 'Completed'), ('postponed', 'Postponed')], default='pending', max_length=250)),
|
||||||
|
('cancelled_reason', models.TextField(default='NA')),
|
||||||
|
('event_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='master_data.eventtype')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventImages',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('is_primary', models.BooleanField(default=False)),
|
||||||
|
('event_image', models.ImageField(upload_to='event_images')),
|
||||||
|
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.event')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
0
events/migrations/__init__.py
Normal file
0
events/migrations/__init__.py
Normal file
42
events/models.py
Normal file
42
events/models.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
from django.db import models
|
||||||
|
from master_data.models import EventType
|
||||||
|
|
||||||
|
class Event(models.Model):
|
||||||
|
created_date = models.DateField(auto_now_add=True)
|
||||||
|
name = models.CharField(max_length=200)
|
||||||
|
description = models.TextField()
|
||||||
|
start_date = models.DateField()
|
||||||
|
end_date = models.DateField()
|
||||||
|
|
||||||
|
latitude = models.DecimalField(max_digits=9, decimal_places=6)
|
||||||
|
longitude = models.DecimalField(max_digits=9, decimal_places=6)
|
||||||
|
pincode = models.CharField(max_length=10)
|
||||||
|
district = models.CharField(max_length=100)
|
||||||
|
state = models.CharField(max_length=100)
|
||||||
|
place = models.CharField(max_length=200)
|
||||||
|
|
||||||
|
is_bookable = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
is_eventify_event = models.BooleanField(default=True)
|
||||||
|
outside_event_url = models.URLField(default='NA')
|
||||||
|
|
||||||
|
event_type = models.ForeignKey(EventType, on_delete=models.CASCADE)
|
||||||
|
event_status = models.CharField(max_length=250, choices=[
|
||||||
|
('created', 'Created'),
|
||||||
|
('cancelled', 'Cancelled'),
|
||||||
|
('pending', 'Pending'),
|
||||||
|
('completed', 'Completed'),
|
||||||
|
('postponed', 'Postponed'),
|
||||||
|
], default='pending')
|
||||||
|
cancelled_reason = models.TextField(default='NA')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} ({self.start_date})"
|
||||||
|
|
||||||
|
class EventImages(models.Model):
|
||||||
|
event = models.ForeignKey(Event, on_delete=models.CASCADE)
|
||||||
|
is_primary = models.BooleanField(default=False)
|
||||||
|
event_image = models.ImageField(upload_to='event_images')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.event_image}"
|
||||||
11
events/urls.py
Normal file
11
events/urls.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'events'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', views.EventListView.as_view(), name='event_list'),
|
||||||
|
path('add/', views.EventCreateView.as_view(), name='event_add'),
|
||||||
|
path('<int:pk>/edit/', views.EventUpdateView.as_view(), name='event_edit'),
|
||||||
|
path('<int:pk>/delete/', views.EventDeleteView.as_view(), name='event_delete'),
|
||||||
|
]
|
||||||
28
events/views.py
Normal file
28
events/views.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from django.views import generic
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from .models import Event
|
||||||
|
from .forms import EventForm
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
|
||||||
|
class EventListView(LoginRequiredMixin, generic.ListView):
|
||||||
|
model = Event
|
||||||
|
context_object_name = 'events'
|
||||||
|
template_name = 'events/event_list.html'
|
||||||
|
paginate_by = 10
|
||||||
|
|
||||||
|
class EventCreateView(LoginRequiredMixin, generic.CreateView):
|
||||||
|
model = Event
|
||||||
|
form_class = EventForm
|
||||||
|
template_name = 'events/event_form.html'
|
||||||
|
success_url = reverse_lazy('events:event_list')
|
||||||
|
|
||||||
|
class EventUpdateView(LoginRequiredMixin, generic.UpdateView):
|
||||||
|
model = Event
|
||||||
|
form_class = EventForm
|
||||||
|
template_name = 'events/event_form.html'
|
||||||
|
success_url = reverse_lazy('events:event_list')
|
||||||
|
|
||||||
|
class EventDeleteView(LoginRequiredMixin, generic.DeleteView):
|
||||||
|
model = Event
|
||||||
|
template_name = 'events/event_confirm_delete.html'
|
||||||
|
success_url = reverse_lazy('events:event_list')
|
||||||
8
manage.py
Normal file
8
manage.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import os, sys
|
||||||
|
def main():
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eventify.settings')
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
execute_from_command_line(sys.argv)
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
7
master_data/admin.py
Normal file
7
master_data/admin.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from .models import EventType
|
||||||
|
|
||||||
|
@admin.register(EventType)
|
||||||
|
class EventTypeAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('id','event_type')
|
||||||
|
search_fields = ('event_type',)
|
||||||
7
master_data/forms.py
Normal file
7
master_data/forms.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from django import forms
|
||||||
|
from .models import EventType
|
||||||
|
|
||||||
|
class EventTypeForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = EventType
|
||||||
|
fields = ['event_type']
|
||||||
24
master_data/migrations/0001_initial.py
Normal file
24
master_data/migrations/0001_initial.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2025-11-26 22:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventType',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('event_type', models.CharField(max_length=50)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'master_data_event_type',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
0
master_data/migrations/__init__.py
Normal file
0
master_data/migrations/__init__.py
Normal file
10
master_data/models.py
Normal file
10
master_data/models.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class EventType(models.Model):
|
||||||
|
event_type = models.CharField(max_length=50, null=False, blank=False)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.event_type
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'master_data_event_type'
|
||||||
11
master_data/urls.py
Normal file
11
master_data/urls.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'master_data'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('event-types/', views.EventTypeListView.as_view(), name='event_type_list'),
|
||||||
|
path('event-types/add/', views.EventTypeCreateView.as_view(), name='event_type_add'),
|
||||||
|
path('event-types/<int:pk>/edit/', views.EventTypeUpdateView.as_view(), name='event_type_edit'),
|
||||||
|
path('event-types/<int:pk>/delete/', views.EventTypeDeleteView.as_view(), name='event_type_delete'),
|
||||||
|
]
|
||||||
27
master_data/views.py
Normal file
27
master_data/views.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
from django.views import generic
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from .models import EventType
|
||||||
|
from .forms import EventTypeForm
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
|
||||||
|
class EventTypeListView(LoginRequiredMixin, generic.ListView):
|
||||||
|
model = EventType
|
||||||
|
template_name = 'master_data/event_type_list.html'
|
||||||
|
context_object_name = 'categories'
|
||||||
|
|
||||||
|
class EventTypeCreateView(LoginRequiredMixin, generic.CreateView):
|
||||||
|
model = EventType
|
||||||
|
form_class = EventTypeForm
|
||||||
|
template_name = 'master_data/event_type_form.html'
|
||||||
|
success_url = reverse_lazy('master_data:event_type_list')
|
||||||
|
|
||||||
|
class EventTypeUpdateView(LoginRequiredMixin, generic.UpdateView):
|
||||||
|
model = EventType
|
||||||
|
form_class = EventTypeForm
|
||||||
|
template_name = 'master_data/event_type_form.html'
|
||||||
|
success_url = reverse_lazy('master_data:event_type_list')
|
||||||
|
|
||||||
|
class EventTypeDeleteView(LoginRequiredMixin, generic.DeleteView):
|
||||||
|
model = EventType
|
||||||
|
template_name = 'master_data/event_type_confirm_delete.html'
|
||||||
|
success_url = reverse_lazy('master_data:event_type_list')
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Django>=4.2
|
||||||
|
Pillow
|
||||||
0
static/.gitkeep
Normal file
0
static/.gitkeep
Normal file
BIN
templates.zip
Normal file
BIN
templates.zip
Normal file
Binary file not shown.
17
templates/accounts/login.html
Normal file
17
templates/accounts/login.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card p-4 shadow-sm">
|
||||||
|
<h3 class="text-center mb-3">Login</h3>
|
||||||
|
<form method="post" novalidate>
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
<div class="mb-3">{{ form.username.label_tag }}{{ form.username }}</div>
|
||||||
|
<div class="mb-3">{{ form.password.label_tag }}{{ form.password }}</div>
|
||||||
|
<button class="btn btn-primary w-100">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
7
templates/accounts/user_confirm_delete.html
Normal file
7
templates/accounts/user_confirm_delete.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<h3>Delete User</h3>
|
||||||
|
<p>Are you sure you want to delete <strong>{{ object.username }}</strong>?</p>
|
||||||
|
<form method="post">{% csrf_token %}<button class="btn btn-danger">Yes, delete</button>
|
||||||
|
<a class="btn btn-secondary" href="{% url 'accounts:user_list' %}">Cancel</a></form>
|
||||||
|
{% endblock %}
|
||||||
9
templates/accounts/user_form.html
Normal file
9
templates/accounts/user_form.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<h3>{% if object %}Edit{% else %}Add{% endif %} User</h3>
|
||||||
|
<form method="post">{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<button class="btn btn-primary">Save</button>
|
||||||
|
<a class="btn btn-secondary" href="{% url 'accounts:user_list' %}">Cancel</a>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
27
templates/accounts/user_list.html
Normal file
27
templates/accounts/user_list.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="d-flex justify-content-between mb-3">
|
||||||
|
<h3>Users</h3>
|
||||||
|
<a class="btn btn-success" href="{% url 'accounts:user_add' %}">Add User</a>
|
||||||
|
</div>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead><tr><th>#</th><th>Username</th><th>Email</th><th>Phone</th><th>Role</th><th>Actions</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
{% for u in users %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ forloop.counter }}</td>
|
||||||
|
<td>{{ u.username }}</td>
|
||||||
|
<td>{{ u.email }}</td>
|
||||||
|
<td>{{ u.phone_number }}</td>
|
||||||
|
<td>{{ u.role }}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-sm btn-primary" href="{% url 'accounts:user_edit' u.pk %}">Edit</a>
|
||||||
|
<a class="btn btn-sm btn-danger" href="{% url 'accounts:user_delete' u.pk %}">Delete</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td colspan="6">No users yet.</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
44
templates/base.html
Normal file
44
templates/base.html
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||||
|
<title>Eventify</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="{% url 'dashboard' %}">Eventify</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navmenu">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navmenu">
|
||||||
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'dashboard' %}">Dashboard</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'master_data:event_type_list' %}">Categories</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'events:event_list' %}">Events</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'accounts:user_list' %}">Users</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<li class="nav-item"><a class="nav-link" href="#">{{ user.username }}</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link text-danger" href="{% url 'logout' %}">Logout</a></li>
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{% url 'login' %}">Login</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="container mt-4">
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-{{ message.tags }}">{{ message }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
23
templates/dashboard.html
Normal file
23
templates/dashboard.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="row text-center">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card p-3 shadow-sm">
|
||||||
|
<h5>Total Events</h5>
|
||||||
|
<h2>{{ total_events }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card p-3 shadow-sm">
|
||||||
|
<h5>Total Categories</h5>
|
||||||
|
<h2>{{ total_categories }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card p-3 shadow-sm">
|
||||||
|
<h5>Total Users</h5>
|
||||||
|
<h2>{{ total_users }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
7
templates/events/event_confirm_delete.html
Normal file
7
templates/events/event_confirm_delete.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<h3>Delete Event</h3>
|
||||||
|
<p>Are you sure you want to delete <strong>{{ object.name }}</strong>?</p>
|
||||||
|
<form method="post">{% csrf_token %}<button class="btn btn-danger">Yes, delete</button>
|
||||||
|
<a class="btn btn-secondary" href="{% url 'events:event_list' %}">Cancel</a></form>
|
||||||
|
{% endblock %}
|
||||||
9
templates/events/event_form.html
Normal file
9
templates/events/event_form.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<h3>{% if object %}Edit{% else %}Add{% endif %} Event</h3>
|
||||||
|
<form method="post">{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<button class="btn btn-primary">Save</button>
|
||||||
|
<a class="btn btn-secondary" href="{% url 'events:event_list' %}">Cancel</a>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
27
templates/events/event_list.html
Normal file
27
templates/events/event_list.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="d-flex justify-content-between mb-3">
|
||||||
|
<h3>Events</h3>
|
||||||
|
<a class="btn btn-success" href="{% url 'events:event_add' %}">Add Event</a>
|
||||||
|
</div>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead><tr><th>#</th><th>Name</th><th>Type</th><th>Dates</th><th>Place</th><th>Actions</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
{% for e in events %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ forloop.counter }}</td>
|
||||||
|
<td>{{ e.name }}</td>
|
||||||
|
<td>{{ e.event_type }}</td>
|
||||||
|
<td>{{ e.start_date }} - {{ e.end_date }}</td>
|
||||||
|
<td>{{ e.place }}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-sm btn-primary" href="{% url 'events:event_edit' e.pk %}">Edit</a>
|
||||||
|
<a class="btn btn-sm btn-danger" href="{% url 'events:event_delete' e.pk %}">Delete</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td colspan="6">No events found.</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
7
templates/master_data/event_type_confirm_delete.html
Normal file
7
templates/master_data/event_type_confirm_delete.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<h3>Delete Category</h3>
|
||||||
|
<p>Are you sure you want to delete <strong>{{ object.event_type }}</strong>?</p>
|
||||||
|
<form method="post">{% csrf_token %}<button class="btn btn-danger">Yes, delete</button>
|
||||||
|
<a class="btn btn-secondary" href="{% url 'master_data:event_type_list' %}">Cancel</a></form>
|
||||||
|
{% endblock %}
|
||||||
9
templates/master_data/event_type_form.html
Normal file
9
templates/master_data/event_type_form.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<h3>{% if object %}Edit{% else %}Add{% endif %} Category</h3>
|
||||||
|
<form method="post">{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<button class="btn btn-primary">Save</button>
|
||||||
|
<a class="btn btn-secondary" href="{% url 'master_data:event_type_list' %}">Cancel</a>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
24
templates/master_data/event_type_list.html
Normal file
24
templates/master_data/event_type_list.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="d-flex justify-content-between mb-3">
|
||||||
|
<h3>Event Categories</h3>
|
||||||
|
<a class="btn btn-success" href="{% url 'master_data:event_type_add' %}">Add Category</a>
|
||||||
|
</div>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead><tr><th>#</th><th>Event Type</th><th>Actions</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
{% for c in categories %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ forloop.counter }}</td>
|
||||||
|
<td>{{ c.event_type }}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-sm btn-primary" href="{% url 'master_data:event_type_edit' c.pk %}">Edit</a>
|
||||||
|
<a class="btn btn-sm btn-danger" href="{% url 'master_data:event_type_delete' c.pk %}">Delete</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td colspan="3">No categories yet.</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user