1

I'm trying to make a simple shop for myself without popular modules. And stack on next things.

I have two models - articles (kind of "product" in here) and user with custom profile model. So what I need is when User goes to Article page, he can push the button ("Buy" maybe) and that article model connects to User. So he can see it on his profile page. Also, I need a check function in template, indicates that User bought Article or not (some kind "if-else").

I'm already hooked up my Article model to my User Profile model with ForeignKey, but right now I don't know where the next point to move. Can someone help?

My model userprofile:

    import PIL

    from django.db import models
    from django.contrib.auth.models import User
    from PIL import Image
    from django.db import models
    from article.models import Article

    class UserProfile(models.Model):  
        user = models.OneToOneField(User)
        user_picture = models.ImageField(upload_to='users', blank=False, null=False, default='users/big-avatar.jpg')
        user_balance = models.IntegerField(default=0)
        user_articles = models.ForeignKey(Article, blank=True, null=True)

    User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u) [0])

My forms.py for userprofile

from django import forms
from userprofile.models import User
from userprofile.models import UserProfile

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name',)

class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ('user_picture', 'user_balance')

My view for userprofile

from django.shortcuts import render, render_to_response, redirect
from django.shortcuts import HttpResponseRedirect, Http404, HttpResponse
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from django.core.context_processors import csrf

from userprofile.forms import User
from userprofile.forms import UserForm
from userprofile.forms import UserProfileForm

def userprofile(request, username):
    u = User.objects.get(username=username)
    if request.POST:
        user_form = UserForm(request.POST, instance=request.user)
        user_profile = UserProfileForm(request.POST, request.FILES, instance=request.user.profile)
        if user_form.is_valid() and user_profile.is_valid():
            user_form.save()
            user_profile.save()
    else:
        user_form = UserForm(instance=request.user,
            initial={
                'first_name': request.user.first_name,
                'last_name': request.user.last_name,
                'email': request.user.email,
            })
        user = request.user
        profile = user.profile
        user_profile = UserProfileForm(instance=profile)

    return render_to_response('profile.html', {'user_form': user_form, 'user_profile': user_profile}, context_instance=RequestContext(request))

And my model article, that needs to be hooked up:

import PIL

from django.db import models
from django.contrib.auth.models import User
from PIL import Image
from django.db import models

class Article(models.Model):
    class Meta():
        db_table = 'article'

    article_title = models.CharField(max_length=200, blank=False, null=False)
    article_anchor = models.CharField(max_length=200, blank=False, null=False)
    article_image = models.ImageField(upload_to='items', blank=False, null=False)
    article_users = models.IntegerField(default=0)

class Comments(models.Model):
    class Meta():
        db_table = 'comments'

    comments_date = models.DateTimeField()
    comments_text = models.TextField(verbose_name=u'')
    comments_article = models.ForeignKey(Article)
    comments_from = models.ForeignKey(User)
s.spirit
  • 343
  • 1
  • 7
  • 19
  • Your ForeignKey is the wrong way round: it needs to live on Article and point to UserProfile. Otherwise a user could only have one article (but an article would have many users), which is clearly wrong. – Daniel Roseman May 01 '15 at 12:26
  • Thx, Daniel. The relations between the models - a little bit confusing for me sometimes) – s.spirit May 01 '15 at 15:17

1 Answers1

3

Just to clarify a few things:

  1. I assume a user can purchase multiple articles
  2. An article can belong to many users

If this is the case, then you have a many-to-many relationship between the user model and the article model. So what you can do is to modify your Article model:

class Article(models.Model):
    class Meta():
        db_table = 'article'

    article_title = models.CharField(max_length=200, blank=False, null=False)
    article_anchor = models.CharField(max_length=200, blank=False, null=False)
    article_image = models.ImageField(upload_to='items', blank=False, null=False)
    article_users = models.ManyToManyField(User) # <- use ManyToManyField instead of IntegerField

Another approach is to create a OrderHistory model to store who (User) purchased what(Article):

class OrderHistory(models.Model):
    user = models.ForeignKey(User)
    article = models.ForeignKey(Article)
    purchase_date = models.DateTimeField(auto_now_add=True)

Let's assume that you used the first approach. Modifying models is not enough. There are a few things you need to add to your site:

  1. A webpage for displaying a list of Articles for users to purchase

    • So you need a template file that shows a list of avaiable articles
    • you need a view function to render this page
    • this page will contain a list of articles and a way for users to select which article they want to buy via checkbox (or many buy buttons beside each article, your choice). So bascially your template will have a element that contains a list of articles and a 'buy' button to POST this data back to server
  2. When a user clicks on the 'Buy' button, the data is submitted to a url that you need to define in the urls.py

    • add a new url in your urls.py and hook it to a view function
    • the view function will use request.user to identify which user it is and use the data in request.POST to figure out the article ids that's being purchased.
    • then you need to find the article from the database using

      article = Article.objects.filter(pk=the_id_you_received_from_POST) 
      article.article_users.add(request.user)
      article.save()
      
  3. return a success message

Read this link before you start:

https://docs.djangoproject.com/en/1.8/topics/db/examples/many_to_many/

EDIT: As Daniel pointed out, remove the following line from UserProfile user_articles = models.ForeignKey(Article, blank=True, null=True)

You have to think about if the relationship between a user and an article is one-to-many or many-to-many. models.ForeignKey means one user can buy many articles, but once an article has been purchased, it can only belong to one user.(which is probably not what you want)


To pass data from a webpage to your view function, there are two ways:

  1. Through GET request: parameters are appended to the end of the url, here is a good example of how it is done in Django: Capturing url parameters in request.GET

  2. Through POST request: usually, you would have a form on the page and a submit button to submit the data to a predefined URL:

    <form action = "url_for_handling_POST_request" method = "post">
    

Please follow Django's tutorial: - https://docs.djangoproject.com/en/1.8/intro/tutorial04/ - https://docs.djangoproject.com/en/1.8/topics/forms/#processing-the-data-from-a-form

In your case, you should use POST request. so read the documentation above. It contains an example that matches to what you need.

Note: don't forget to insert the CSRF token inside your form or Django will complain:

    <form ...>
        {% csrf_token %}
    </form>
Community
  • 1
  • 1
Cheng
  • 16,824
  • 23
  • 74
  • 104
  • Cheng, thanks very much for discribe the logic of models relations. I think, I need to try both ways... And for now, I think that second way is better, cause it automatically gives to me full stats about actions of all users. Isn't it? It can be really useful for managment... – s.spirit May 01 '15 at 15:23
  • @s.spirit I would use the second approach personally. But the first one works too. It really depends on want you need. The benefit of the 2nd approach, as you said, stores all of the purchase history in one table. So if this is something you want your users to see, then use the 2nd approach. – Cheng May 01 '15 at 16:07
  • Sorry for such noob question, but how to submit data to url that I created? Can u write an example? Am I need to wrap template of Article to `
    ` tag or something? Or just add an `` tag?
    – s.spirit May 03 '15 at 18:27