Python-en-equipo / MarketPlace

Aplicación web Tipo Marketplace, registro de usuarios, post y compras de usuarios y vendedores desarrollada con Django y Tailwind
11 stars 1 forks source link

Rama ragnarok y los cambios críticos realizados #30

Open CodeRagnarok07 opened 2 years ago

CodeRagnarok07 commented 2 years ago

Cambios de términos

  1. ya que no es un simple ecommers mas bien una red de vendedores es mas útil usar el termino Marketplace
  2. los vendedores no quieren llamarse empleados, así que solo vendedores

Frontend

los templetes fueron alojados fuera de las apps para tener mayor control a la hora de solo trabajar en el frontend

Backend

propongo dividir los servicios en los siguientes:

  1. usuarios

    1. registro
    2. login
    3. panel de usuarios
    4. comentarios
    5. etc
  2. Productos

    1. productos
    2. imagenes
    3. categorias
  3. sistema de compras

    1. carrito de compras
    2. sistema de pagos
    3. sistema de envió
    4. sistema de remuneración a los vendedores
CodeRagnarok07 commented 2 years ago

Cambio la base de datos local a Postgres

1. instala postgresql en tu entorno local

2. Alternar entre la base de datos local y la base de datos de produccion

DEBUG = os.environ["DEBUG"] 
# Recuerda establecer esta variable en produccion heroku config:set DEBUG=False

if DEBUG:
    DATABASES = {
        "default": {
            "ENGINE": "django.db.backends.postgresql_psycopg2",
            "NAME": "marketplace", # db postgres es la que se usa para administrar todas las tablas asi que la cambio
            "USER": "postgres",
            "PASSWORD": "123123",
            "HOST": "localhost",
            "PORT": "5432",
        }
    }

else:
    DATABASES = {
        "default": {
            "ENGINE": "django.db.backends.postgresql_psycopg2",
            "NAME": os.environ["NAME_DB_HEROKU"],
            "USER": os.environ["USER_DB_HEROKU"],
            "PASSWORD": os.environ["PASSWORD_DB_HEROKU"],
            "HOST": os.environ["HOST_DB_HEROKU"],
            "PORT": "5432",
        }
    }

puede que debas crear la base de datos "marketplace" en postgresql local

CodeRagnarok07 commented 2 years ago

29

Urls optimizadas

'config/urls.py'

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("ecommerce.urls")),
    path("user/", include("users.urls")),
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

#

'apps/ecommerce/urls.py'

from django.urls import path

from .views import show_my_page,  product_edit_view, product_create, product_detail_view, product_deletion

#app_name = "ecommerce"

urlpatterns = [
    path("", show_my_page, name="home"),
    path("edit/<int:product_id>", product_edit_view, name="product_edit"),
    path("new/", product_create, name="product_create"),
    path("detail/<int:product_id>", product_detail_view, name="product_detail"),
    path("delete/<int:product_id>", product_deletion, name="product_delete"),

]

'navbar.html'

<header class="py-3 bg-dark text-white">
    <div class="container">
        <div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
            <a class="d-flex mb-2 mb-lg-0 mx-3 btn btn-outline-light"
            href="{% url 'home' %}"> AisModa marketPlace</a>

            <form class="col-12 col-lg-auto mb-3 mb-lg-0 me-lg-auto">
                <input type="search" class="form-control form-control-dark" placeholder="Search..." aria-label="Search">
            </form>

            <div class="col-lg-6 col-mb-8 d-flex justify-content-end ">
                <!--  ni idea como lo hise funcionar :) -->

                {% if request.user.is_authenticated and request.user.is_staff%}
                <span class="user-msg h3 mx-3"> Hello, {{request.user}}</span>
                <a class="btn btn-warning m-1" href="{% url 'logout' %}"> Logout </a>
                <a class="btn btn-warning m-1" href="{% url 'product-create' %}">new product</a>
                {% elif request.user.is_authenticated %}
                <span class="user-msg h3 mx-3"> Hello, {{request.user}}</span>
                <a class="btn btn-warning m-1" href="{% url 'logout' %}"> Logout </a>
                {% else %}
                <a class="btn btn-outline-light me-2 m-3" href="{% url 'login' %}"> Login </a>
                {% endif %}
            </div>
        </div>

        <ul role="group"
            class="nav btn-group btn-group-sm  col-12 col-lg-auto me-lg-auto justify-content-center justify-content-lg-start mb-md-0  m-2">
            <li><a href="#" class="btn btn-outline-secondary">categoria1</a></li>
            <li><a href="#" class="btn btn-outline-secondary">categoria2</a></li>
            <li><a href="#" class="btn btn-outline-secondary">categoria3</a></li>
        </ul>

    </div>
</header>
CodeRagnarok07 commented 2 years ago

29

alojamiento de las apps en una subcarpeta

config/sttings.py


sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

# Application definitionds

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "storages",
    "ecommerce",
    "users",
]

image

CodeRagnarok07 commented 2 years ago

28

Adjunto un esquema temporal de la base de datos

image

CodeRagnarok07 commented 2 years ago

Cambie el entorno virtual a django-environ

  1. Esto permite usar las variables de entorno desde el entrono virtual sin tener que ejecutarlo desde afuera con pipenv run, lo cual ayuda a que el vscode ubique el entorno vitual cada ves que abre una nueva terminal
  2. instalacion pipenv django-environ
  3. settings.py
import environ                      # add this
import os
import sys
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

env = environ.Env(                  # add this
    # set casting, default value
    DEBUG=(bool, False)             # add this
)

environ.Env.read_env(os.path.join(BASE_DIR, '.env'))  #add this

SECRET_KEY = env('DJANGO_KEY')

# SECURITY WARNING: don't run with debug turned on in production!

DEBUG = env('DEBUG')
también cabe destacar que este paquete lee las variables sin comillas y pegado a la igualdad
NAME_DB_HEROKU = "d866t8ka1g995" <= antes
NAME_DB_HEROKU=d866t8ka1g995 <= Ahora

Registro de usuario > registro de vendedor

  1. la finalidad es que cada usuario pueda comprar productos y tenga opción a registrarse como vendedor, a demás que cada producto tenga la autoria de un vendedor
  2. models.py
class Seller(models.Model):
    profile = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name="seller", primary_key=True)
    seller_name = models.CharField(max_length=50)
    #is_active = models.BooleanField(default=False)

    def __str__(self):
        return f"{self.seller_name}"
  1. form
class SellerForm(forms.ModelForm):
    class Meta:
        model = Seller
        fields = ("seller_name",)

Registro de Vendedor: cambie el uso de el decorador que necesita ser staff por condicionales y autentificacion

@login_required
def seller_register(request):
    """ registro disponible para clientes, debe estar registrado en la plataforma para acceder a este registro"""
    if request.user.seller == False :
        seller_form = SellerForm()
        if request.method == "POST":
            seller_form = SellerForm(request.POST)
            if seller_form.is_valid():
                seller = seller_form.save(commit=False)
                seller.profile = request.user
                seller.save()
                return redirect("ecommerce:home")
    else:
        return redirect("ecommerce:home")
registro de usuario como vendedor, si el usuario ya es vendedor y quiere acceder a esta url lo redirecciona a home
{% if request.user.is_authenticated and request.user.seller is false %}
  <li class="nav-item"><a href="{% url 'users:seller_register' %}" class="nav-link px-2 text-muted">vendor_register</a></li>
{% endif %}
tambien preveo eso en el html

categorías de Productos + categorias + vendedor del producto

models de productos:

class Category(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255, null=True, blank=True)
    ordering = models.IntegerField(default=0) # para tener un control sobre el orden de las categorias
    class Meta:
        ordering = ['ordering']
    def __str__(self):
        return self.title
se ordenan a voluntad por el campo ordering

llaves foraneas de categorias y seller en productos

class Product(models.Model):
    category = models.ForeignKey(Category, related_name='products', on_delete=models.CASCADE)
    seller = models.ForeignKey(Seller, related_name="products", on_delete=models.CASCADE)

    title = models.CharField(max_length=250)
    description = models.TextField()
    price = models.PositiveIntegerField(validators=[MinValueValidator(50)])
    slug = models.SlugField(null=True, blank=True) # se va a generar automaticamente mas adelante

algoritmo que genera urls unicas

def save(self, *args, **kwargs):
        # LOGICA PARA LAS URLS UNICAS        
        original_slug = slugify(self.title) # creacion automatica apartir del titulo
        queryset = Product.objects.all().filter(slug__iexact=original_slug).count() 
        # "Busca si hay otro slug que conincida con el mismo original_slug"
        count = 1
        slug = original_slug
        # (queryset) si encuentra otro con este mismo slug
        while(queryset): 
            slug = original_slug + '-' + str(count)
            count += 1
            # vuelve a hacer la verificacion
            queryset = Product.objects.all().filter(slug__iexact=slug).count() 
        self.slug = slug 
        super(Product, self).save(*args, **kwargs)