I have a UserPost List View which is a view for a specific user's posts. I am looping the posts of this specific user but I want to add this user's profile details like profile image and other details like email.
So, I am not sure on how to add the user details of the user's post names as designer not the logged-in user.
I can add the user/designer details in every looped post but I don't want it to be repeated with every post I just want it to appear once just like {{ view.kwargs.username }} as this page is realted only to this user/designer
Here is the models.py
class Post(models.Model):
designer = models.ForeignKey(User, on_delete=models.CASCADE, related_name="post")
title = models.CharField(max_length=100, unique=True)
here is the profile model related to every user
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
first_name = forms.CharField()
last_name = forms.CharField()
class Meta:
model = User
fields = ['username', 'first_name', 'last_name',
'email']
here is the views for the userpostlist which is filtered by a specific user/designer not the logged in user
class UserPostListView(ListView):
model = Post
template_name = "user_posts.html"
context_object_name = 'posts'
queryset = Post.objects.filter(admin_approved=True)
paginate_by = 6
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(designer=user, admin_approved=True).order_by('-date_posted')
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
has_items = Item.objects.filter(designer__username=self.kwargs['username']).exists()
context['has_items'] = has_items
return context
here is the template
{% if has_items %}
<h1 class="display-4">Hello, this is {{ view.kwargs.username }} </h1>
<img class="profile_image" src={{ designer.profile.image.url }}> <----------- I want it to appear
{{ designer.email }}<----------- I want it to appear
{% else %}
Show nothing
{% endif %}
{% for post in posts %}
Post details
{% endfor %}
You can add this to the context:
from django.contrib.auth import get_user_model
class UserPostListView(ListView):
model = Post
template_name = 'user_posts.html'
context_object_name = 'posts'
queryset = Post.objects.filter(admin_approved=True)
paginate_by = 6
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).filter(
designer__username=self.kwargs['username']
).order_by('-date_posted')
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['designer'] = designer = get_object_or_404(
get_user_model(),
username=self.kwargs['username']
)
context['has_items'] = Item.objects.filter(designer=designer).exists()
return context
Related
I am trying to display all the categories to appear as a list that I can click and select from, just an exact replica of what I have in my admin panel, but it still display's as a list that isn't clickable.
forms.py
class ProfileEditForm(forms.ModelForm):
"""
Form for updating Profile data
"""
class Meta:
model = Profile
fields = [
"first_name",
"last_name",
"about_me",
"profile_image",
"username",
"email",
"categories",
]
first_name = forms.CharField(label="First Name", max_length=63, required=False)
last_name = forms.CharField(label="Last Name", max_length=63, required=False)
about_me = forms.CharField(label="About Me", max_length=511, required=False)
email = forms.EmailField(label="Email", disabled=True)
username = forms.CharField(label="Username", disabled=True)
profile_image = forms.ImageField(required=False)
categories = forms.ModelMultipleChoiceField(
queryset=Category.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple(),
)
profile.models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
first_name = models.CharField(max_length=63, blank=False)
last_name = models.CharField(max_length=63, blank=False)
about_me = models.CharField(max_length=511, blank=True)
categories = models.ManyToManyField(
Category, related_name="user_categories", symmetrical=False
)
categories.models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=63)
created = models.DateTimeField(auto_now_add=True, blank=True, null=True)
last_modified = models.DateTimeField(auto_now=True, blank=True, null=True)
def __str__(self):
return self.name
def __unicode__(self):
return self.name
class Meta:
verbose_name_plural = "Categories"
settings.html
<div class='row'>
<div class="col s12 m6">
{{form.categories.errors}}
{{form.categories.label_tag}}
{{form.categories}}
</div>
</div>
What I hope to achieve
What I get
You need to create the form itself:
<form method='post'>
</form>
And print each field on a new line:
{{ form.as_p }}
is a security check.
{% csrf_token %}
In the view, I left get_context_data. In it, you can add values to the context, for example, like this:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['rubrics'] = Car.objects.all()
Replace bboard with the name of the folder where your templates are placed.
I have this: templates/bboard which are in the application folder.
In the view for the form, the CreateView class is used, in which: template_name - the name of the template for displaying the page, form_class - the form class is indicated, success_url - where to return in case of successful saving of the form (in this case, this is the same page with the form), get_context_data - the template context (you can print it out and see what's inside).
And if your model has fields: first_name, last_name, about_me, email, username, profile_image, then it is enough that you have specified the fields variable in the class Meta class. You don't need to re-create them in the form.
template_name = 'bboard/tam_form.html'#bboard replace with your prefix
Templates
<form method='post'>
{{form.categories.errors}}
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value='adding'>
</form>
views.py
from .forms import *
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
class Profile(CreateView):
template_name = 'bboard/settings.html'#bboard replace with your prefix
form_class = ProfileEditForm
success_url = reverse_lazy('test')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
urls.py
from django.urls import path
from .views import *
urlpatterns = [
path('test/', Profile.as_view(), name='test'),
]
Update 13.11.2022
This is how my form looks like when I go to the address:
http://localhost:8000/test/
But the form is not submitted. I don't have much experience with this. I can assume that forms.ModelForm expects that the model has such fields, because if you delete the lines with email, username, profile_image and also remove them from the fields and add 'user' to the field, then the data will be saved in the database (checked).
As I said earlier, if the fields are declared in fields, then you do not need to define them again (if you leave them, the form will also be saved). This is what the form class looks like:
class ProfileEditForm(forms.ModelForm):
class Meta:
model = Profile
fields = [
'user',
'first_name',
'last_name',
'about_me',
'categories',
]
categories = forms.ModelMultipleChoiceField(
queryset=Category.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple(),
)
View.py
class Register(TemplateView):
template_name = 'registration.html'
def get(self, request, *args, **kwargs):
form = CreateForm()
return render(request, self.template_name, {'form': form})
#staticmethod
def post(request):
try:
data = request.POST.get
user = User(
first_name=data('first_name'),
last_name=data('last_name'),
username=data('username').strip(),
email=data('email'),
)
user.set_password(data('password').strip())
user.save()
request.session["user_id"] = user.id
return HttpResponse(' Save successfully ')
except Exception as c:
return HttpResponse("Failed : {}".format(c), 500)
Form.py
role_choice= (("Customer", "Customer"), ("Employee", "Employee"))
class CreateForm(forms.Form):
first_name = forms.CharField(label="Enter Your First Name", max_length=30, required=True)
last_name = forms.CharField(label="Enter Your Last Name", max_length=30, required=True)
username = forms.CharField(required=True, widget=forms.TextInput())
email = forms.CharField(required=True, widget=forms.TextInput())
password = forms.CharField(required=True, widget=forms.PasswordInput())
role = forms.ChoiceField(choices=role_choice, widget=forms.RadioSelect())
class Customer(forms.Form):
contact = forms.IntegerField(label="Enter your contact number", required=True, )
amount = forms.IntegerField(required=True, min_value=500)
type = forms.ChoiceField(choices=choice)
Model.py
class Customers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
contact = models.BigIntegerField()
amount = models.BigIntegerField()
type = models.CharField(max_length=1)
Template
{% extends "home.html" %}
{% load crispy_forms_tags %}
{% block title %}Create Account{% endblock %}
{% block content %}
<div>
{% csrf_token %}
{{ form|crispy }}
<button type="submit">Submit</button><br>
</div>
{% endblock %}
After the registration when user select customer option after sumbit the form i go to customer page if user select employee option he/she go to employee page but i don't know how to do this
First of all, I strongly advice not to write all the views, etc. yourself. Django already has a lot of tooling inplace. It has a UserCreationForm [Django-doc] that can be slighly modified. For example:
# app/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
class RoleUserCreationForm(UserCreationForm):
ROLES = (
('Customer', 'Customer'),
('Employee', 'Employee')
)
role = forms.ChoiceField(choices=ROLES, widget=forms.RadioSelect())
class Meta(UserCreationForm.Meta):
fields = (*UserCreationForm.Meta.fields, 'first_name', 'last_name')
We can here thus add the extra fields for first_name and last_name as well.
Now we can make use of this in a CreateView [Django-doc], and override the form_valid(..) method [Django-doc]:
# app/views.py
from app.forms import RoleUserCreationForm
from django.contrib.auth import get_user_model
from django.shortcuts import redirect
from django.views.generic.edit import CreateView
class RegisterView(CreateView):
model = get_user_model()
form_class = RoleUserCreationForm
def form_valid(self, form):
request.session['user_id'] = self.object.id
if form.cleaned_data['role'] == 'Customer':
return redirect('name-of-customer-view')
else:
return redirect('name-of-employee-view')
Where you replace the 'name-of-customer-view' and 'name-of-employee-view' with the name of these views respectively.
I created a field in my signup form asking users for a link to their linkedin profile.
I created a page that returns a list of all the users (mentor users) and noticed that I cannot access the linkedin link. I am not sure if its because I have not saved the link or I am not accessing it correctly.
This is what I have in models.py
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
...
class Mentor(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True)
linkedin = models.URLField(max_length=200,null=True,blank=True)
def __str__(self):
return "Profile of user {}".format(self.user.username)
#receiver(post_save,sender=User)
def create_or_update(sender, instance, created, **kwargs):
if created:
post_save.connect(create_or_update, sender=User)
forms.py
class TeacherSignUpForm(UserCreationForm):
email = forms.EmailField(max_length=100)
first_name = forms.CharField(max_length=100)
last_name = forms.CharField(max_length=100)
linkedin = forms.URLField(max_length=200)
class Meta(UserCreationForm.Meta):
model = User
fields = ('email', 'username', 'first_name', 'last_name')
def save(self, commit=True):
self.instance.is_teacher = True
user = super(UserCreationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()
mentor = Mentor.objects.get_or_create(
user=user,
linkedin=self.cleaned_data['linkedin']
)
return user
#basic form
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
views.py (teachers.py)
class TeacherSignUpView(CreateView):
model = User
form_class = TeacherSignUpForm
template_name = 'registration/signup_form.html'
def get_context_data(self, **kwargs):
kwargs['user_type'] = 'teacher'
return super().get_context_data(**kwargs)
def form_valid(self, form):
user = form.save()
login(self.request, user)
return redirect('teachers:app-instructor-dashboard')
students.py (views)
#get list of mentors
def mentor_list(request):
mentors = User.objects.filter(is_teacher=True).select_related('mentor')
template_name = 'classroom/students/mentor_list.html'
context = {'mentors': mentors}
return render(request, template_name, context)
the html where I generate the list of mentors:
<ul id="menu-header-menu">
{% for user in mentors %}
<li>{{ user.first_name }} {{ user.last_name }}</li>
{% endfor %}
</ul>
From this list I only get the user's first and last name but cannot get their linkedin profile
You have use mentor in this line mentors = User.objects.filter(is_teacher=True).select_related('mentor') but not defined mentor anywhere.
Table are connected with this line:
user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True)
add related_name .
user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True, related_name='mentor')
Then makemigrations and migrate(I Hope you are familiar). Everything else is fine.
Also, print this to verify.
def mentor_list(request):
mentors = User.objects.filter(is_teacher=True).select_related('mentor')
# Edited, remember this is just for checking. this is not required
for user in mentors:
try:
print(user.mentor.linkedin)
except:
pass
template_name = 'classroom/students/mentor_list.html'
context = {'mentors': mentors}
return render(request, template_name, context)
I've been looking for this for few days and I couldn't solve it, so here is my problem:
I'm trying to create a product using just CreateView in views.py for now (My idea is to create forms and pass everything to a function in views.py), but there is one field that I want it to be auto-filled with the logged user ('owner'). I've tried using the get_initial in the createView for now, but it doesn't work.
I want to say that this it actually creates a form in which I have to fill all the fields and it works fine, but I want to auto-fill the 'owner' field with the current user logged in.
For now I tried to use the get_initial as I said before, but seems that it does not work. I also tried lots of things that I've seen here, in stackoverflow, but any of them worked for me.
Here I put all the relevant code, but if you need anything else please, ask for it and I'll upload it.
This is my views.py:
# view for the product entry page
class ProductCreate(CreateView):
model = Product
fields = ['owner', 'category', 'tag', 'name', 'content_tweet']
success_url = reverse_lazy('index')
def get_form(self, form_class=None):
form = super(ProductCreate, self).get_form(form_class)
return form
def get_initial(self):
return {
'owner': self.request.user,
}
def dispatch(self, request, *args, **kwargs):
if not request.user.is_superuser or request.user.is_vendor:
raise PermissionDenied()
return super().dispatch(request, *args, **kwargs)
This is the model I'm using in models.py:
class Product(models.Model):
owner = models.ForeignKey(CustomUser, on_delete=models.PROTECT)
name = models.CharField(_('Product Name'), max_length=150)
category = models.ManyToManyField(Category)
tag = models.ManyToManyField(Tag)
content_tweet = models.CharField(_('Content Tweet'), max_length=150, blank=True)
content_abstract = models.CharField(_('Content Abstract'), max_length=3000, blank=True)
canvas_1 = models.FileField(upload_to='documents/canvas_1/', blank=True)
price_tweet = models.IntegerField(_('Tweet Price in Tokens'), default=0)
price_abstract = models.IntegerField(_('Abstract Price in Tokens'), default=50)
price_canvas_1 = models.IntegerField(_('Canvas 1 Price in Tokens'), default=500)
it_exist = models.BooleanField(_('is an existing idea?'), default=False)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this product should be treated as active. '
'Unselect this instead of deleting products.'
),
)
history = HistoricalRecords()
class Meta:
unique_together = ('name', 'owner')
def get_categories(self):
return ",".join([str(p) for p in self.category.all()])
def get_tags(self):
return ",".join([str(p) for p in self.tag.all()])
def __str__(self):
return self.name
And this is the template I'm using (for now) in my XX.html:
{% for field in form %}
<div class="form-group">
<div >
<span class="text-danger la">{{ field.errors }}</span>
</div>
<label >{{ field.label_tag }}</label>
<div class="col-sm-10">{{ field }}</div>
</div>
{% endfor %}
def form_valid(self, form):
form.instance.owner = self.request.user
return super(ProductCreate, self).form_valid(form)
override form_valid method of CreateView as above
I'm having trouble using the UpdateView for a view consisting of a form and formset.
I have the following models: Item and Picture.
Picture is defined as:
class Picture(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255, blank=False)
content_type = models.ForeignKey(ContentType, verbose_name="content type",
related_name="content_type_set_for_%(class)s")
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey("content_type", "object_id")
I have several models that contain pictures. For example, in the Item model:
class Item(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255, blank=False)
pictures = generic.GenericRelation(Picture)
I have the following ItemCreateForm:
class ItemCreateForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ItemCreateForm, self).__init__(*args, **kwargs)
class Meta:
model = Item
The PictureForm:
class PictureForm(forms.ModelForm):
id = forms.IntegerField(widget=forms.HiddenInput)
def __init__(self, *args, **kwargs):
super(PictureForm, self).__init__(*args, **kwargs)
def save(self):
data = self.cleaned_data
obj = Picture(**data);
# do something to obj
# obj.save()
class Meta:
model = Picture
fields = ['id', 'name']
And the view:
class ItemUpdateView(UpdateView):
form_class = ItemCreateForm
template_name = 'item/new.html'
model = Item
success_url = '/items/'
def get_context_data(self, **kwargs):
context = super(ItemUpdateView, self).get_context_data(**kwargs)
item = context['object']
# Dont' create any extra forms when showing an update view
PictureFormSet = formset_factory(PictureForm, extra=0)
return {'form': kwargs['form'],
'picture_formset': UploadFormSet(initial = [ model_to_dict(a) for pic in item.pictures.all()])}
def post(self, request, *args, **kwargs):
self.object = self.get_object()
item_form = ItemCreateForm(request.POST, instance=self.object)
if item_form.is_valid():
item = item_form.save(commit=False)
item.save()
# How do update the pictures?
This is my urls.py:
url(r'^items/(?P<pk>\d+)/update/$', ItemUpdateView.as_view(), name='item_update')
The template:
<form action="" method="post" enctype="multipart/form-data">
{% for field in form %}
# do something
{% endfor %}
{{ picture_formset.management_form }}
{% for form in picture_formset.forms %}
# do something
{% endfor %}
<input name="commit" type="submit" value="Submit" />
</form>
I'm new to Django.
The user can dynamically(via jQuery) add/remove pictures through the Picture form in the single template that is used to display the item and multiple pictures.
1 I had to include the id as a hidden field for the picture, otherwise the pictures will be inserted instead of an Update. QN: Is there a better way to do this?
2 How do I update the picture model? Currently request.POST doesn't have all the fields in the model, thus the model is complaining of NULL fields? I'm totally at lost how to deal with formset in an UpdateView and is not the main form, like a simple example of UpdateView with the pk in the url.
PictureFormSet = formset_factory(PictureForm)
picture_formset = PictureFormSet(request.POST, request.FILES)
for picture_form in picture_formset.forms:
picture_form.save()