Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django user model extension in an ecommerce application

Tags:

python

django

I have a django ecommerce project that works fine till I decided to improve it. I let users place order on certain services but every time they place an order they have to always input their details (name, emil, address etc) so I decided to upgrade the application so that user can add their billing address and it can be referenced in the order or continue as a guest.

Model

class Order(models.Model):
    first_name = models.CharField(max_length=50) 
    last_name = models.CharField(max_length=50)
    email = models.EmailField()
    address = models.CharField(max_length=250) 
    postal_code = models.CharField(max_length=20) 
    city = models.CharField(max_length=100)
    created = models.DateTimeField(auto_now_add=True) 
    updated = models.DateTimeField(auto_now=True) 
    paid = models.BooleanField(default=False)

class OrderItem(models.Model):
    order = models.ForeignKey(Order, related_name='items')
    product = models.ForeignKey(Product,related_name='order_items')
    price = models.DecimalField(max_digits=10, decimal_places=2)
    quantity = models.PositiveIntegerField(default=1)

view

def order_create(request):
    cart = Cart(request)
    if request.method == 'POST':
        form = OrderCreateForm(request.POST) 
        if form.is_valid():
            order = form.save() 
            for item in cart:
            OrderItem.objects.create(order=order, product=item['product'],price=item['price'], quantity=item['quantity'])
            cart.clear()
            return render(request,'order/created.html', {'order': order})
    else:
        form = OrderCreateForm()
    return render(request, 'order/create.html',{'cart': cart, 'form': form})

I then created an account app and extended django user so that user can register address and mobile so that the user does not have to type it every time he/she wants to place an order.

my new model is

class Order(models.Model):
    account = models.ForeignKey(Account, related_name='user_account')
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    paid = models.BooleanField(default=False)
    coupon = models.ForeignKey(Coupon, related_name='orders',null=True,blank=True)
    discount = models.IntegerField(default=0,validators=[MinValueValidator(0), MaxValueValidator(100)])

I am confused on how to code for my view. any assistance would help and I also have

def admin_order_detail(request, order_id):
    order = get_object_or_404(Order, id=order_id)
    #account = Account.objects.filter(request.user)
    context = {
        'order': order,
        }
    template = 'order/detail.html'
    return render(request,template,context)

to be able to view the order details in the admin area but I am only able to extend the FUll name, Email and phone number. Any help would be appreciated. Thanks in advance

A copy of all codes from github https://github.com/Olar19/ecommerce

like image 871
King Avatar asked Oct 28 '17 20:10

King


People also ask

How does Django handle multiple users?

In short, you will always have one User model to handle authentication. Do not spread username and passwords across multiple models. Usually extending the default User model and adding boolean flags such as is_student and is_staff work for most cases. Permissions can be managed at a higher level using view decorators.

Should I use default Django user model?

Whenever you are starting a new Django project, always swap the default user model. Even if the default implementation fit all your needs. You can simply extend the AbstractUser and change a single configuration on the settings module.

Should you create custom user model in Django?

It's highly recommended to set up a custom User model when starting a new Django project. Without it, you will need to create another model (like UserProfile ) and link it to the Django User model with a OneToOneField if you want to add new fields to the User model.


2 Answers

This is a great idea to leverage the built in User object. Django is very "batteries included" meaning that it comes with much more out-of-the-box than say Flask and to me a large part of that the User auth system.

Normally you'll extend the User object with a one-to-one field which in your context looks like the Account object.

more detail on one-to-one fields (from the docs)

If you were B2B vice B2C then you may want the Account object to house the company name and then assign employees to that account where the Employee object would then be the extension from User.

So assuming the Account object looks something like:

class Account(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(max_length=500, blank=True)
    ...

You could then access Account and User Objects from the Order Object.

order = get_object_or_404(Order, id=order_id)
username = order.user_account.username

or for permissions type stuff

orders = Order.objects.filter(user_account__user = request.user)
like image 50
sahutchi Avatar answered Sep 21 '22 15:09

sahutchi


What you are trying to do is something very common and reasonable to want to do. There are two main ways to add additional information to the Django User model. 1) You can override the django User model and define your own custom model or 2) you can create another model, say UserData, and have UserData have a OneToOneField connection with Django's User model. Thus, for every user, there is an associated UserData that stores the additional field information you need. It is difficult and not recommended to do option 1 in the middle of an existing project, so I would recommend transitioning to option 2.

The django documentation is very good on how to create a UserData model and link it to the User model. You can read about it here. A key note on this approach is that you need to a) go back and create a UserData object for all existing users (if any exist) and b) need to make sure to create a UserData object every time a user registers a user account on your website.

class UserData(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, default=0, related_name="userdata")
    # other fields ...

Now in your views, you can access the user data as such:

def admin_order_detail(request):
    ud = request.user.userdata

When you then want to access user data in a view, it is

I just looked over your code and it looks like you are not currently use Django's User system to have users register and login. I think a first step would be to read over the django documentation on the user auth system (here). Then, try and integrate user auth into your application. Finally, you can then create a custom userdata class to extend the user model.

Good luck!

like image 26
Rohan Varma Avatar answered Sep 24 '22 15:09

Rohan Varma