I am in the process of learning Django. I am trying to create a simple directory web app. I am able to print out all the users details for the main directory page. However, I want to add a feature that when a person logs into the directory app they are brought to their 'profile' page where they will be able to see all their own details e.g. business name, profile pic.
I know how to retrieve the default fields e.g. username and email. But cannot seem to retrieve the custom fields that I declared myself. Here is my attempts so far...
Models.py:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfileInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.DO_NOTHING)
#additional classes
business_name = models.CharField(max_length=191,blank=True)
trade = models.CharField(max_length=191,blank=True)
portfolio_site = models.URLField(blank=True)
profile_pic = models.ImageField(upload_to='profile_pics',blank=True)
def __str__(self):
return self.user.username
Views.py:
#login_required
def profile(request):
profile = UserProfileInfo.objects.filter(user=request.user)
context = { 'profile': profile }
return render(request, 'dir_app/profile.html',context)
Profile.html:
<div class="container-fluid text-center">
{% for p in profile %}
<h3>{{p.business_name}}</h3>
{% endfor %}
</div>
Since UserProfileInfo is related to User via OneToOneField, you can have one UserProfileInfo per User. So, instead of Filter, you can simply get your desired UserProfileInfo object through your current (logged in) User as follows.
views.py,
profile = UserProfileInfo.objects.get(user=request.user)
Also, before you can get a request.user object, you have to make sure that your user is authenticated and logged in. Otherwise, you might get None in place of a User object and therefore, no associated UserProfileInfo.
Since it is a OneToOneField there is only one Profile object for a User, you thus can obtain this with:
#login_required
def profile(request):
profile = request.user.userprofileinfo
return render(request, 'my_template.html',{'profile': profile})
Then in the template, you render it with:
{{ profile.business_name }}
you can use it directly on template without sending it f:
{{request.user.userprofile}}
Related
I am building a website where user come and login, after login user publish articles with admin approval . I do not know how to do it. I made a user authentication system where user can login. But i do not know how to make him post data with admin approval.
Therefor you need a condition in your model to be able to query the approved objects (blog posts) to display.
A basic approach could look as follows:
Create a model to store the blog posts and its logic to the database
# models.py
class Blog_Post(models.Model):
text = models.CharField(max_length=500)
is_approved = models.BooleanField(default=False)
def __str__(self):
return self.name
Register your model in the admin so you can approve them via django-admin
from django.contrib import admin
from myproject.myapp.models import Blog_Post
admin.site.register(Blog_Post)
Create a view to only fetch blog posts that have been approved by an admin
# views.py
def get_blog_post(request):
# Only fetch the blog posts that are approved
queryset = Blog_Post.objects.filter(is_approved=True)
return render(request, 'your_html.html', {'queryset' : queryset})
Render the blog posts in your template
# your_html.html
{% for blog_post in queryset %}
<div>{{ blog_post.text }}</div>
{% endfor %}
That's a Good one. You can enable this with adding a new column to your database like onapproval Set it as an boolean variable like 0 or 1 either true or false. Then check for it. If it's true you can set the status as approved and if it is not set it as not approved. The same process will also takes place in admin panel too.
I'm developing to-list app with registration . I have two models : Model for User and Model for Tasks . I add new task throw Ajax to one user it adding and displaying for every user. Is there any solutions ? Here some pictures
Here is my code:
models.py
class Task(models.Model):
title=models.IntegerField()
date = models.DateTimeField(default=datetime.now,blank=True)
is_published=models.BooleanField(default=True)
class CustomUser(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
image=models.FileField(upload_to='photos/%Y/%m/%d/',null=True,blank=True)
views.py
if request.method == 'POST' and request.POST['form_type'] == 'task':
if request.is_ajax():
addtask = AddTask(request.POST)
if addtask.is_valid():
user = request.user.id
addtask.objects.filter(user=user).cleaned_data
addtask.objects.filter(user=user).save()
task_object = Task.objects.filter(user=user)(addtask)
return JsonResponse({'error': False, 'data': task_object})
else:
print(addtask.errors)
return JsonResponse({'error': True, 'data': addtask.errors})
else:
error = {
'message': 'Error, must be an Ajax call.'
}
return JsonResponse(error, content_type="application/json")
addtask = AddTask()
task = Task.objects.order_by('-date').filter(is_published=True)
html page
{% if task %}
{% for tas in task %}
Task content
{% endfor %}
{% else %}
{% endif %}
Maybe you should add relation to CustomUser in Task model and filter tasks by owner in view before to render data to template?
class Task(models.Model):
title=models.IntegerField()
date = models.DateTimeField(default=datetime.now,blank=True)
is_published=models.BooleanField(default=True)
user=models.ForeignKey(CustomUser)
class CustomUser(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
image=models.FileField(upload_to='photos/%Y/%m/%d/',null=True,blank=True)
And in view:
...
addtask = AddTask()
task = Task.objects.filter(is_published=True, user_id=request.user.id).order_by('-date')
So the mistake is that you never connected your CustomUser model with your Task model. They should have a relationship like one to many. Once that is achieved, you have to retrieve only the tasks related to the user of interest from the database and send them to the HTML page. Then only the tasks related to one particular user will be displayed.
If you want to create CustomUser model, you should create a class and inherit it from AbstractBaseUser or AbstractUser(django documentation).
Your Task model hasn't relationships with CustomUser. You create AddTask(?) instance but didn't bind it with any user.
You did not submit a view which renders HTML template, but I think that your query is something like Tasks = Task.objects.all() which return all tasks.
This is how you should create CustomUser model
This is documentation about relationships in Django
This is about making queries in Django
Update and solution below.
I've been looking for a solution but I'm not finding anything that sticks out.
I've created a Profile model which is linked to the standard User model via one-to-one field which is working in admin. I want to pull all fields/data for both models into a single queryset. I'm trying to create a user editing form and I want to pull in all fields for User and Profile based on the current logged in user and display those fields which I will have a page to edit and save those fields.
What are the best options to achieve this, simple is better.
class Profile(models.Model):
address = models.blablabla
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
def profile_edit(request):
form = UserProfileForm(request.POST or None)
instance = Profile.objects.all().filter(user__username=request.user).values # This is the place I need to create a single queryset.
if request.method == "POST" and form.is_valid():
form = UserProfileForm(request.POST, instance=instance)
user_form = form.save()
print("POST event")
else:
form = UserProfileForm(instance=instance)
print(form)
return render(request, 'frontend/profile_edit.html', {'form': form})
I'm manually creating the forms in the template so I would like to have something like {{ form.username }} {{ form.profile.address }} or something like that. I'm likely doing things poorly, I'm new to django.
UPDATE
Complete solution
Complete steps to gain access to user and profile models in code and template.
I decided not to replace the User model with my own in case I missed out on features provided by django. It also seemed to complicate things that might hurt later on. So I've gone with the separate UserProfile model and attached it to the User model. Here is what I did for future readers.
models.py
from django.db.models.signals import post_save
class UserProfile(models.Model):
#take note of the related_name='profile' this is used to reference the fields in code and template.
#Each field of type 'text' I added default='' at the end, I got an error when it was int based so I removed the flag for that field. I read this might cause an error when you try and auto-create the profile, see what works for you and you might not want it.
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
country = models.CharField(max_length=2, blank=True, null=True, default='')
...
# Auto-create the profile upon user account creation. It's important to start with a fresh database so the user and profile ID's match.
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
# Create your models here.
#In code, you can access your user and profile field data like so.
request.user.profile.fieldname
request.user.fieldname
In template you can do the same
{{ user.fieldname }}
{{ user.profile.fieldname }}
There's no need for a query here at all - you don't want a queryset, you want a single instance.
In this case, request.user.profile will give you the entire Profile object related to the current user.
I am building a small blog using django.I want to build a function that allow post author to delete and update their own posts.
Then I find django has LoginMixin for generic view,but it only block those who don't login.
My article Model is like below
class Article(models.Model):
author = models.ForeignKey(User)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=50)
context = models.TextField()
genre_choice = (('O','Others'),('P','Programming'),('L','Learning'),('E','Entertainment'))
genre = models.CharField(max_length=2,choices=genre_choice,default='O')
def __str__(self):
return "{} - {}".format(self.title,self.author)
def get_absolute_url(self):
return reverse("article-detail",args=str(self.id))
This is the generic article detail view.
class ArticleDetail(DetailView):
model = Article
I firstly want to add something like this in the detail template:
{% if article.author == user.username%}
<!-- Some a tag that directs to the update view -->
{% endif %}
Then I realize that this just hides the a tag ,it can't stop other users to touch the update url simply change the url.
Is there anyway in django can restricted the update and delete permissions to the original user by simply using generic view?Even if they directly enter the update url,they will be rejected.
Override get_queryset in your UpdateView, so that the user can only access items that they authored. Use the LoginRequiredMixin to ensure that only logged-in users can access the view.
from django.contrib.auth.mixins import LoginRequiredMixin
class UpdateArticle(LoginRequiredMixin, UpdateView):
model = Article
def get_queryset(self):
queryset = super(UpdateArticle, self).get_queryset()
queryset = queryset.filter(author=self.request.user)
return queryset
In the template, I would compare the author_id with the user's primary key to decide whether to show the link or not.
{% if article.author_id == user.pk %}
One option is to create your own mixin/decorator to check if the logged user is the author, if not then reload/show a message etc.
I believe a safer way now would be to use built-in mixin UserPassesTestMixin. In particular, you can inherit it in your class and change its test_func() to check for the author. Don't forget to also inherit LoginRequiredMixin to make sure the user is logged in:
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
class UpdateArticle(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Article
def test_func(self):
thisArticle = self.get_object()
if self.request.user == thisArticle.author:
return True
return False
If a user who is not the author attempts to update the article, '403 Forbidden' Error is returned which is just what you want in such a situation.
I'm using django's built-in contrib.auth module and have setup a foreign key relationship to a User for when a 'post' is added:
class Post(models.Model):
owner = models.ForeignKey('User')
# ... etc.
Now when it comes to actually adding the Post, I'm not sure what to supply in the owner field before calling save(). I expected something like an id in user's session but I noticed User does not have a user_id or id attribute. What data is it that I should be pulling from the user's authenticated session to populate the owner field with? I've tried to see what's going on in the database table but not too clued up on the sqlite setup yet.
Thanks for any help...
You want to provide a "User" object. I.e. the same kind of thing you'd get from User.objects.get(pk=13).
If you're using the authentication components of Django, the user is also attached to the request object, and you can use it directly from within your view code:
request.user
If the user isn't authenticated, then Django will return an instance of django.contrib.auth.models.AnonymousUser. (per http://docs.djangoproject.com/en/dev/ref/request-response/#attributes)
Requirements --> Django 3, python 3
1) For add username to owner = models.ForeignKey('User') for save that, in the first step you must add from django.conf import settings above models.py and edit owner = models.ForeignKey('User') to this sample:
class Post(models.Model):
slug = models.SlugField(max_length=100, unique=True, null=True, allow_unicode=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, on_delete=models.CASCADE)
2) And for show detail Post, special owner name or family or username under the post, you must add the following code in the second step in views.py:
from django.shortcuts import get_object_or_404
.
.
.
def detailPost(request,slug=None):
instance = get_object_or_404(Post, slug=slug)
context = {
'instance': instance,
}
return render(request, template_name='detail_post.html', context=context)
3) And in the third step, you must add the following code for show user information like user full name that creates a post:
<p class="font-small grey-text">Auther: {{ instance.owner.get_full_name }} </p>
now if you want to use user name, you can use {{ instance.owner.get_username }}
or if you want to access short name, you can use {{ instance.owner.get_short_name }}.
See this link for more information.