ArtGallery is a social media platform where artists come together to show their personal/AI-generated/digital works.
Back-end: Django, DRF Front-end: HTML, CSS
The images used in this project are produced through my personal Midjourney subscription. The images are not for sale nor I am monetizing these pictures in any way. The project files do NOT include the images.
Some images are from pixabay. None of the images are for sale or used commercially. I hold the license for personal use.
I do not own the UI kit. You can find it here: Mumble UI Kit.
Windows
- Go to the official Python website: Python
- Download the latest version of Python for Windows by clicking on the "Download Python" button. Choose the version that is appropriate for your system (32-bit or 64-bit).
- Open the downloaded installer and follow the installation wizard. Make sure to select the option "Add Python to PATH" during the installation process.
MacOS
- Go to the official Python website: Python
- Download the latest version of Python for Windows by clicking on the "Download Python" button. Choose the version that is appropriate for your system (32-bit or 64-bit).
- Open the downloaded installer and follow the installation wizard. Make sure to select the option "Install for all users" and "Add Python to PATH" during the installation process.
Linux
- Open a terminal window.
- Use the package manager for your Linux distribution to install Python. For
example, on Ubuntu and Debian, you can use the command
sudo apt-get install python3
to install Python 3. - Verify that Python is installed by running the command
python3 --version
in the terminal. If Python is installed correctly, you should see the version number of Python that you installed.
Depending on how you want to use this project, you may want to run it locally on your machine. If so follow the steps on this section:
- Install virtualenv: Once you have installed Python, you can install virtualenv using pip. Open your terminal (Command Prompt for Windows) and type:
pip install virtualenv
MacOS & Linux
- Create a virtual environment: To create a virtual environment, go to the directory where you want to create it and run the following command:
virtualenv myenv
Here, myenv is the name of the virtual environment. You can choose any name you want.
- Activate the virtual environment: To activate the virtual environment, run the following command:
source myenv/bin/activate
Windows
On Windows, the command is slightly different:
myenv\Scripts\activate.bat
- Open the command prompt
- Navigate to the directory that contains the requirements.txt file.
- Run the following command:
pip install -r requirements.txt
Run inside the directory containing manage.py
file:
python manage.py runserver
Prepare:
python manage.py makemigrations
Run:
python manage.py migrate
Field | Parameters | Type |
---|---|---|
user | on_delete=models.CASCADE, null=True, blank=True | OneToOneField |
name | max_length=200, blank=True, null=True | CharField |
max_length=500, blank=True, null=True | EmailField | |
username | max_length=200, blank=True, null=True | CharField |
location | max_length=200, blank=True, null=True | CharField |
short_intro | max_length=200, blank=True, null=True | CharField |
bio | blank=True, null=True | TextField |
profile_image | null=True, blank=True, upload_to="profiles/", default="profiles/user-default.png" | ImageField |
social_portfolio | max_length=200, blank=True, null=True | CharField |
social_twitter | max_length=200, blank=True, null=True | CharField |
social_linkedin | max_length=200, blank=True, null=True | CharField |
social_website | max_length=200, blank=True, null=True | CharField |
created | auto_now_add=True | DateTimeField |
id | default=uuid.uuid4, unique=True, primary_key=True, editable=False | UUIDField |
Field | Parameters | Type |
---|---|---|
owner | on_delete=models.CASCADE, null=True, blank=True | ForeignKey |
name | max_length=200, blank=True, null=True | CharField |
description | blank=True, null=True | TextField |
created | auto_now_add=True | DateTimeField |
id | default=uuid.uuid4, unique=True, primary_key=True, editable=False | UUIDField |
Field | Parameters | Type |
---|---|---|
sender | on_delete=models.SET_NULL, null=True, blank=True | ForeignKey |
recipient | on_delete=models.SET_NULL, null=True, blank=True, related_name="messages" | ForeignKey |
name | max_length=200, null=True, blank=True | CharField |
max_length=200, null=True, blank=True | EmailField | |
subject | max_length=200, null=True, blank=True | CharField |
body | TextField | |
is_read | default=False, null=True | BooleanField |
created | auto_now_add=True | DateTimeField |
id | default=uuid.uuid4, unique=True, primary_key=True, editable=False | UUIDField |
Field | Parameters | Type |
---|---|---|
owner | on_delete=models.SET_NULL, null=True, blank=True | ForeignKey |
title | max_length=200 | CharField |
description | null=True, blank=True | TextField |
featured_image | null=True, blank=True, default="default.jpg" | ImageField |
demo_link | max_length=2000, null=True, blank=True | CharField |
source_link | max_length=2000, null=True, blank=True | CharField |
tags | blank=True | ManyToManyField |
vote_total | default=0, null=True, blank=True | IntegerField |
vote_ratio | default=0, null=True, blank=True | IntegerField |
created | auto_now_add=True | DateTimeField |
id | default=uuid.uuid4, unique=True, primary_key=True, editable=False | UUIDField |
Field | Parameters | Type |
---|---|---|
owner | on_delete=models.CASCADE, null=True | ForeignKey |
artwork | on_delete=models.CASCADE | ForeignKey |
body | null=True, blank=True | TextField |
value | max_length=200, choices=VOTE_TYPE | CharField |
created | auto_now_add=True | DateTimeField |
id | default=uuid.uuid4, unique=True, primary_key=True, editable=False | UUIDField |
Field | Parameters | Type |
---|---|---|
name | max_length=200 | CharField |
created | auto_now_add=True | DateTimeField |
id | default=uuid.uuid4, unique=True, primary_key=True, editable=False | UUIDField |
Created with MindMeister.
If no user is logged in, the "Inbox" and "Account" feature will not be available. This is achieved by using the @login_required decorator to enforce authentication and authorization.
If an unauthenticated user tries to access the view, they will be redirected to the login page specified in the login_url argument.
@login_required(login_url="login")
def inbox(request):
profile = request.user.profile
message_requests = profile.messages.all()
unread_count = message_requests.filter(is_read=False).count()
context = {"message_requests": message_requests, "unread_count": unread_count}
return render(request, "users/inbox.html", context)
I used the built-in Django user creation form.
- It takes care of a lot of things, such as password hashing.
Whenever a user is trying register, it form is kept in a variable called
user
. This form is then checked to see if the username is all lower case, so that the app will not have multiple users with the same name but with different cases. This temporary instance saving is done by form.save(commit=False)
If the user is logged out, they see a different profile page compared to a logged in user. If the user who is logged in is viewing their own profile page, they get to edit their profile.
After registering you will receive your confirmation email:
Set up the e-mail configurations inside the settings.py file:
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = # smtp of your e-mail provider.
EMAIL_PORT =
EMAIL_USE_TLS = True
EMAIL_HOST_USER = # e-mail address
EMAIL_HOST_PASSWORD = # e-mail password
After registering the user will directly go to a page to setup their account.
- If a user logs in, a session is created and they get redirected to the previous page they were on.
- If a user logs out, the session is destroyed and they redirected to the home page.
- In each case depending on their authorisations, they get restrictions, For instance, if the user logs in, they will not be allowed to get into the login page.
- If a user is logged out, they won't be allowed to see the "Add Project" button. Moreover, they will not be allowed to go to
updateArtwork
,createArtwork
, deleteArtwork pages.
The project does not use session based authentication, instead it uses JSON Web Tokens.
Pagination is available on multiple pages:
- Artists page
- Artworks page
You can rate artworks. Every rating is then calculated using the "get_vote_count" method:
@property
def get_vote_count(self):
reviews = self.review_set.all()
up_votes = reviews.filter(value="up").count()
total_votes = reviews.count()
ratio = (up_votes / total_votes) * 100
self.vote_total = total_votes
self.vote_ratio = ratio
self.save()
You can send and receive messages.
I had an issue with form fields. I wanted to input a class in each form. Although, my fields in the form were being looped dynamically so that it had no code duplication. After researching, I found out that there are multiple ways of doing this. You may want to use JavaScript and locate these fields using their ID's and then modify each field. Another option would be to customise the models forms. Django's model forms are highly customisable, if you look through Django GitHub repo. That is how I tackled that problem (inside form.py file, you can overwrite the init method and go from there).
Every time a user is created, a Profile also gets created because of the 1:1 relationship between these two models and Django executes this creation automatically. This case should also occur the other way around and to do so, signals are used. Inside of the Users app, models are followed by post_save and post_delete methods to listen to the Profile. Each time a delete is called on the Profile, the User will be deleted. This signal is mostly useful for keeping consistency within admin actions. Since the users are only exposed to the Profile model and not the User model.
Example:
def updateUser(sender, instance, created, **kwargs):
profile = instance
user = profile.user
if created is False:
user.first_name = profile.name
user.username = profile.username
user.email = profile.email
user.save()
I used Django documentation to create flash messages. These use sessions, they are one time messages.
Use case examples:
- Failed login attempt, where I used messages.error()
- Successful account registration, where I used messages.success()
Users can do CRUD operations. I used "_" in templates to specify that these files are responsible for CRUD. Users can CRUD: - Skills - User information
Aside from the character, text limitations; there are some limitations worth mentioning in the system to prevent errors which were found during tests.
- The amount of distinct skills a user can display on the "Artists" page must be limited since the personal info block is extendable by design. Used 'profile.skill_set.all|slice:"5"' while looping through the tags.
JavaScript Use Cases: When I was building the paginator, it would not work coherently with search. Therefore, I used javascript to query both the page number and the searchquery together. First I got the search form and the page links. Then I used the event handler to pass these links at the click event.
- Deployment.
If you would like to add any extra features to the optimisation simulation, feel free to fork and create a pull request. Thank you!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Erol Gelbul - Website
Project Link: ArtGallery