Connect one model to another - django

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)

Just to clarify a few things:
I assume a user can purchase multiple articles
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:
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
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()
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:
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
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>

Related

ValueError: Cannot assign "'1'": "Post.user" must be a "User" instance

I am doing a group project for a bootcamp and we just started Django for the back-end. We also are using React for front-end. Our project is basically a knockoff reddit.
We have a User model:
`from django.db import models
class User(models.Model):
firstname = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
email = models.CharField(max_length=100, unique=True)
username = models.CharField(max_length=32, unique=True)
password = models.CharField(max_length=255)
def __str__(self):
return '%s' % (self.username)`
and a Post model:
`from django.db import models
from auth_api.models import User
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=255)
formBody = models.TextField(null=True, blank=True)
imageURL = models.CharField(max_length=200, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)`
Our Post Serializers(pretty unfamiliar with this):
`from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
user = serializers.CharField(required=True)
class Meta:
model = Post
fields = ('id', 'user', 'title', 'formBody', 'imageURL', 'created',)`
And our Post Views:
`from django.shortcuts import render
from rest_framework import generics
from .serializers import PostSerializer
from .models import Post
from auth_api.models import User
class PostList(generics.ListCreateAPIView):
queryset = Post.objects.all().order_by('id')
serializer_class = PostSerializer
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all().order_by('id')
serializer_class = PostSerializer`
The idea was when a user created a post their info would be saved with the post so that way when we display the post we could say who created at. Also we could have a user profile that could see all of their posts. I assumed that what would happen is the user info would get saved inside a object in the user column, but the first way we tried only saved the userID and we couldn't access any of the users info. The second way(what we have now) keeps giving us this error: ValueError: Cannot assign "'1'": "Post.user" must be a "User" instance.The 1 is the userID that we pass in from the frontend of the user that created the post. I am unsure of where to go from here and have been stuck for a while on this. Hopefully I provided enough info

How to query User model by 'custom' fields? (django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor)

I extended the User model using my account app.
Model Account app:
from django.db import models
from django.contrib.auth.models import User
from departments.models import Department
class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(upload_to='profile_pics', blank=True)
department = models.ForeignKey(
Department, on_delete=models.SET_NULL, null=True, related_name='department')
def __str__(self):
return self.user.username
Now I need to send the count of users from the same department to my template...
View:
from django.contrib.auth.models import User
#login_required
def home(request):
context = {
'title': 'Dashboard',
'department_members': 'department_members': User.objects.filter(department=request.user.account.department).count(),
}
return render(request, 'app/dashboard.html', context)\
department_members is always 1 even though I have more users on the same department.
I figure that the problem is that User don't have department field by default, so I can't say User.account.objects.filter(department=request.user.account.department)
I've tried a lot of queries and looked into django docs but I could't find the proper manner on how to retrieve this info.
Anyone have the same problem? Any tips on how I can debug/create my query in a better way?
Thanks to all in advance!
Maybe changing department_members queryset to:
context = {
'title': 'Dashboard',
'department_members': Account.objects.filter(department=request.user.account.department).count() if hasattr(request.user, "account") else 0,
}
Solves your problem.

How to get model-objects using other models in django

I need if user requests to get the following page the response of the request would be the page containing specific posts made by the users who is followed by the user who requests.
I thought to do some actions to do this:
Get the requester
Get the users who are followed by the requester
Get the posts created by the users the who are being followed
In my models.py:
class User(AbstractUser):
image_url = models.CharField(max_length=5000, null=True)
class Follow(models.Model):
follower = models.ForeignKey(
User, on_delete=models.PROTECT, related_name="follower")
following = models.ForeignKey(
User, on_delete=models.PROTECT, related_name='following')
class Post(models.Model):
content = models.CharField(max_length=140)
date_created = models.DateTimeField(auto_now_add=True)
poster = models.ForeignKey(User, on_delete=models.CASCADE)
In my views.py:
def following_page(request, username):
user = User.objects.get(username=username)
f = user.following.all()
posts = Post.objects.filter(poster=f.following)
posts = posts.order_by("-date_created").all()
return render(request, 'network/index.html', {
"posts": posts
})
It says
AttributeError 'QuerySet' object has no attribute 'following'
Should I have to change the model? How to solve the problem?
You can filter with:
from django.contrib.auth.decorators import login_required
#login_required
def following_page(request):
posts = Post.objects.filter(poster__following__follower=request.user)
return render(request, 'network/index.html', {
'posts': posts
})
Since you use the logged in user, one uses request.user, and thus it makes no sense for the view to accept a username.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Query for retrieve data with user fk Django 1.11

I'm trying to retrieve data from user. I have my model like this:
from django.db import models
from django.contrib.auth.models import User
Create your models here.
class informacionFacturacion(models.Model):
usuario = models.ForeignKey(User)
apellidos = models.CharField(max_length=100, default="editar")
nombres = models.CharField(max_length=100, default="editar")
telefono = models.CharField(max_length=100, default="editar")
email = models.EmailField(default="editar", null=False)
direccion_1 = models.CharField(max_length=100, default="editar")
direccion_2 = models.CharField(max_length=100, null=True, blank=True)
provincia = models.CharField(max_length=100, default="editar")
ciudad = models.CharField(max_length=100, default="editar")
codigoPostal = models.CharField(max_length=100, default="editar")
empresa = models.CharField(max_length=100, default="editar")
def __str__(self):
return self.usuario
My form for update user information:
from .models import informacionFacturacion
class informacionFacturacionForm(ModelForm):
class Meta:
model = informacionFacturacion
fields = [
"usuario",
"apellidos",
"nombres",
"telefono",
"email",
"direccion_1",
"direccion_2",
"provincia",
"ciudad",
"codigoPostal",
"empresa",
]
And in my view I have my query like this
from django.contrib.auth.decorators import login_required
from .models import informacionFacturacion
from .forms import informacionFacturacionForm
#login_required
def datosPersonales(request):
form = informacionFacturacionForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
query = informacionFacturacion.objects.filter(usuario=request.user)
context = {
"titulo": "Datos personales | Cadenas Giordanino S.R.L" + request.user.username,
"body_class": "class= sidebar_main_open sidebar_main_swipe",
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
And this QuerySet is empty.
I need to retrieve this data in the user profile
**UPDATE: ** Full code on post.
**UPDATE 2: ** For displaying the user data on profile, im using a "For loop". This data, is retrieved in "value=" attr of html inputs. If the user has no data, the form dosnt show.
This is the way I wanna show the data. I populated this form from the same form u see here.
Here's when i enter for first time to my profile with no data
Thanks a lot.
Are you sure that request.user is the user you've linked your anotherModel to? If you aren't currently logged in then request.user will be an instance of AnonymousUser. See more in the Documentation: https://docs.djangoproject.com/en/1.11/ref/request-response/#django.http.HttpRequest.user
You can use the Django Shell for testing your models:
$ python manage.py shell
Then make some models:
from django.contrib.auth.models import User
from models import AnotherModel
# Grab a User
user = User.objects.first()
# Create a new anotherModel, linking the user
my_model = AnotherModel(
user=user,
address="whatever"
)
my_model.save()
my_model.user == user
>>> True

Correctly returning object through Many to Many relationship

My objective is to display a readable list of Articles that belong to my user named 'Admin'
In other words, give me all articles that Admin owns. In my sample data I have Admin owning 1 article.
Problem: When I return the object, its a completely unreadable and unhelpful representation of this object. I'm thinking of adding a unicode() method to my model here but I don't know how!!
Model.py:
from django.db import models
from django.contrib.auth.models import User
class Article (models.Model):
question = models.CharField(max_length=255, unique=True, blank=False)
keywords = models.TextField(max_length=500, blank=True, null=True)
def __unicode__(self):
return self.question
class ArticleUserOwnership (models.Model):
article = models.ManyToManyField(Article)
user = models.ManyToManyField(User)
-- you can see here I'm hooking into the admin user table
Views.py:
from django.http import HttpResponse
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
from GeorgiaArticleManager.models import Article, ArticleUserOwnership
from django.shortcuts import render
def myarticles(request):
if request.user.is_authenticated():
# articles of admin with id= 1
my_articles = ArticleUserOwnership.objects.filter(user=1)
context = {'my_articles': my_articles}
return render(request, 'template/myview.html', context)
myview.html:
ul
{% for ArticleUserOwnership in my_articles %}
li{{ ArticleUserOwnership }}/li
{% endfor %}
/ul
In summary of above:
ArticleUserOwnership.objects.filter(user=1) returns me an object that when I display it on myview.html, I just get 'ArticleUserOwnership object'. I'm sure this is the correct returned object but, I'd like to see returned Article.question. For example Admin owns 'test title 1' and I'd like to see this article question field displayed properly.
my_articles = ArticleUserOwnership.objects.filter(user=1)
gives you a list of ArticleUserOwnership instances. If you want of list of articles try this instead:
auo = ArticleUserOwnership.objects.get(user=1) # could raise DoesNotExist
my_articles = auo.article.all() # you should rename this field 'articles'
However, that ArticleUserOwnership model doesn't really make sense, my guess is that what you're really trying to do is this:
from django.db import models
from django.contrib.auth.models import User
class Article (models.Model):
question = models.CharField(max_length=255, unique=True, blank=False)
keywords = models.TextField(max_length=500, blank=True, null=True)
owners = models.ManyToManyField(User, related_name='owned_articles')
def __unicode__(self):
return self.question
You would then access your data like so:
my_articles = user.owned_articles.all()
See the documentation for examples of how to use ManyToManyFields.
try this:
class ArticleUserOwnership (models.Model):
article = models.ManyToManyField(Article)
user = models.ManyToManyField(User)
def __unicode__(self):
return self.article
OR
def __unicode__(self):
return self.article.question