I have added like and dislike button to Song post When like object is not created if some click on like it is showing intigrity error if like object is already there then it is not rendering that to template.
models.py
Codes in models.py
class Song(models.Model):
song_title = models.CharField(max_length=25)
album = models.ForeignKey(Album, related_name='album_name', on_delete=models.CASCADE, blank=True)
singer = models.ManyToManyField(Singer, blank=True)
language = models.CharField(max_length=25)
class VoteManager(models.Manager):
def get_vote_or_unsaved_blank_vote(self,song,user):
try:
return Vote.objects.get(song=song,user=user)
except ObjectDoesNotExist:
return Vote(song=song,user=user)
class Vote(models.Model):
UP = 1
DOWN = -1
VALUE_CHOICE = ((UP, "👍️"),(DOWN, "👎️"),)
like = models.SmallIntegerField(choices=VALUE_CHOICE)
user = models.ForeignKey(User,on_delete=models.CASCADE)
song = models.ForeignKey(Song, on_delete=models.CASCADE)
voted_on = models.DateTimeField(auto_now=True)
objects = VoteManager()
class Meta:
unique_together = ('user', 'song')
views.py
Codes in views.py
class SongDetailView(DetailView):
model = Song
template_name = 'song/song_detail.html'
def get_context_data(self,**kwargs):
ctx = super().get_context_data(**kwargs)
if self.request.user.is_authenticated:
vote = Vote.objects.get_vote_or_unsaved_blank_vote(song=self.object, user = self.request.user)
if vote.id:
vote_url = reverse('music:song_vote_update', kwargs={'song_id':vote.song.id,'pk':vote.id})
else:
vote_url = reverse('music:song_vote_create', kwargs={'song_id':vote.song.id})
vote_form = SongVoteForm(instance=vote)
ctx['vote_form'] = vote_form
ctx['vote_url'] = vote_url
return ctx
class SongUpdateView(UpdateView):
form_class = SongVoteForm
queryset = Song.objects.all()
def get_object(self,queryset=None):
song = super().get_object(queryset)
user = self.request.user
return song
def get_success_url(self):
song_id = self.kwargs.get('song_id')
return reverse('music:song_detail', kwargs={'pk':song_id})
class SongVoteCreateView(View):
form_class = SongVoteForm
context = {}
def post(self,request,pk=None,song_id=None):
vote_obj,created = Vote.objects.get_or_create(pk=pk)
song_obj = Song.objects.get(pk=song_id)
vote_form = SongVoteForm(request.POST, instance=vote_obj)
if vote_form.is_valid():
new_vote = vote_form.save(commit=False)
new_vote.user = self.request.user
new_vote.song = song_obj
return redirect('/album/')
Song_detail.html
codes in song_detail.html
<form action="{{vote_url}}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ vote_form.as_p }}
<button class="btn btn-primary" type="submit" >Vote</button>
</form>
Error Code
This is the error when submitting the like button. Refer here for the traceback
NOT NULL constraint failed: album_vote.song_id
song and user fields are required. So you have to give song and user while creating Vote.
here is full code::
class SongVoteCreateView(View):
form_class = SongVoteForm
context = {}
def post(self,request,pk=None,song_id=None):
song_obj = Song.objects.get(pk=song_id)
vote_obj,created = Vote.objects.get_or_create(song = song_obj, user = request.user)
vote_form = SongVoteForm(request.POST, instance=vote_obj)
if vote_form.is_valid():
vote_form.save()
return redirect('/album/')
also in VoteManager, the code
return Vote(song=song,user=user)
won't create vote, instead you have to use
return Vote.objects.create(song=song,user=user)
Related
I have 2 models, Employee and Leave, where Employee is a foreign key in Leave. Now when an Employee is applying for a Leave, I want the Employee name option to be limited to only the logged-in user rather than all employees. Can I create a custom input with read-only and send user data using {{}}? I'm not able to retrieve data from input group to models.
Here is my code.
models.py:
class Employee(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
no_of_leaves = models.IntegerField(
null=False,
validators=[MinValueValidator(1), MaxValueValidator(24)],
default=24
)
def __str__(self):
return self.user.username
class Leave(models.Model):
employee = models.ForeignKey(Employee, on_delete=models.CASCADE, default="")
start_date = models.DateField(auto_now_add=False)
end_date = models.DateField(auto_now_add=False)
req_date = models.DateTimeField(default=datetime.datetime.now())
approved_by = models.CharField(max_length=100,blank=True)
STATUS_OPTIONS = (
("Approved","Approved"),
("Pending","Pending"),
("Declined","Declined"),
)
approved = models.CharField(max_length=10, choices=STATUS_OPTIONS, default='Pending')
def __str__(self):
return self.employee.user.username
#property
def date_diff(self):
return (self.end_date - self.start_date).days
forms.py:
class leaveForm(forms.ModelForm):
class Meta():
model = Leave
fields = ('employee', 'start_date', 'end_date')
# start_date = forms.DateField(widget=forms.DateInput(attrs={'type': 'date'}))
widgets = {
'start_date': DateInput(attrs={'type': 'date'}),
'end_date': DateInput(attrs={'type': 'date'})
}
views.py:
#login_required
def applyforleave(request):
user=request.user
emp=Employee.objects.get(user=user)
submitted= False
if request.method == 'POST':
leave_form = leaveForm(data=request.POST)
emp_name=employee(data=request.POST)
if leave_form.is_valid() and emp_name.is_valid():
emp_name.save()
start_date = leave_form.cleaned_data.get("start_date")
end_date = leave_form.cleaned_data.get("end_date")
days = (end_date - start_date).days
days_checker = emp.no_of_leaves - days
if 0 < days_checker < emp.no_of_leaves:
leave = leave_form.save()
leave.set_employee
leave.save()
submitted = True
else:
print("error")
else:
print(leave_form.errors)
else:
leave_form = leaveForm()
return render(
request,
'leaveApp/leave.html',
{
'leave_form': leave_form,
'submitted': submitted,
'emp': emp
}
)
leave.html:
<div class="container">
<div class="jumbotron">
<form enctype="multipart/form-data" method="POST">
{% csrf_token %}
{{ leave_form.as_p }}
<input type="submit" name="" value="Submit">
</form>
</div>
</div>
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
user= self.request.user
super(leaveForm, self).__init__(*args, **kwargs)
add the above init in forms.py
labels = {'employee': user}
statistics = forms.Field(
label=user,
)
this in your forms.py
and pass request from views.py
leave_form = leaveForm(request)
You can also check the docs for using the initial parameter
docs
Here is my models.py file.
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.text import slugify
import misaka
from django.contrib.auth import get_user_model
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=255, unique=True)
slug = models.SlugField(allow_unicode=True, unique=True)
description = models.TextField(blank=True, default='')
description_html = models.TextField(editable=False, default='',blank=True)
members = models.ManyToManyField(User, through="CategoryMember")
category_pic = models.ImageField(upload_to = 'category_pics', blank=True)
def __str__(self):
return self.name
# WE are saving the model. But before that we are converting
# the name using slugify and description using misaka.
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
self.description_html = misaka.html(self.description)
super().save(*args, **kwargs)
#get_absolute_url is used because it tell the template
# CreateView to go to the page it is directing.
# for this example it is directing to go to single page of a category.
def get_absolute_url(self):
return reverse("categories:single", kwargs={"slug":self.slug})
class Meta:
ordering = ['name']
class CategoryMember(models.Model):
category = models.ForeignKey(Category, related_name = "memberships", on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name="user_categories", on_delete=models.CASCADE)
def __str__(self):
return self.user.username
class Meta:
unique_together= ("category", "user")
This is some part of views.py file
from django.contrib.auth.models import User
from categories.models import CategoryMember, Category
class UserPosts(ListView):
model = Post
template_name = 'posts/user_post_list.html'
def get_queryset(self):
try:
self.post_user = User.objects.prefetch_related("user_of_post_model").get(
username__iexact=self.kwargs.get("username")
)
except User.DoesNotExist:
raise Http404
else:
return self.post_user.user_of_post_model.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
current_user = UserProfileInfo.objects.filter(
user__id__iexact = self.post_user.id
).get()
i=1
user_categories={}
for member in CategoryMember.objects.all():
if member.user == self.post_user:
user_categories.update({i:member.category.name})
i=i+1
else:
print('not found')
print(user_categories)
if current_user.profile_pic:
profile_pic = True
picture = current_user.profile_pic
edited_picture = get_thumbnail(picture, '350x350', quality=99, format='PNG')
else:
profile_pic = False
root = settings.MEDIA_ROOT
import os
root1 = os.path.join(root, 'profile_pics/no-image.png')
picture = root1
edited_picture = get_thumbnail(picture, '350x350', quality=99, format='PNG')
# resizeimage.resize_cover(picture, [200, 100], validate=False)
# rescale_image(picture,width=100,height=100)
current_user1 = current_user
user_info = {
'current_user':current_user,
'user_categories':user_categories,
'picture':edited_picture,
'profile_pic':profile_pic,
'post_user':self.post_user,
}
context['user_info'] = user_info
return context
After rendering the html page i can see that dictionary has values inside. Here is the values printed in terminal.
not found
not found
not found
not found
not found
{1: 'Regression', 2: 'Classification'}
Now, i want to get user_categories in my django template. i have tried in different approaches but can't get user_categories .
this is some part of my django html file.
<h3>Member of Categories</h3>
{# this line shows error #}
{# {{ userinfo[{{user_categories}}] }} #}
{{ userinfo.user_categories.1 }}
{% for categories in userinfo.user_categories %}
{{categories}}
{% endfor %}
<h5 class="techfont">Post written by {{user_info.post_user.username}} : {{post_list.count}} </h5>
This section only renders user_info.post_user.username but not user_info.user_categories.1
see the text below.
Member of categories.
Post written by abc: 1
user_categories is a dictionary, not a list. So try like this:
{% for idx, categories in userinfo.user_categories.items %}
{{idx}}. {{categories}}
{% endfor %}
As I want to filter on foreign key, I used carmodel with __ in the method dropdownlistsearch() of views.py. When run the code, it tells it must be a field. I don't understand this part. Why do I get this error. And I am using django 1.6.5.
models.py
from django.db import models
class CarInfo(models.Model):0
vin_number = models.CharField(max_length = 17)
model = models.ForeignKey(CarModel)
timestamp = models.DateTimeField(auto_now_add = True, auto_now = False)
updated = models.DateTimeField(auto_now_add = False, auto_now = True)
def __unicode__(self):
return self.vin_number
class CarModel(models.Model):
model = models.CharField(max_length = 60)
def __unicode__(self):
return self.model
views.py
def dropdownsearch(request):
try:
q = request.GET.get('q')
except:
q = None
if q:
cars = CarInfo.objects.filter(carmodel__model__contains=q)
template ='productions/resultstwo.html'
else:
template = 'prodcutions/cars.html'
context = {}
return render(request,template,context)
cars.html
<form action="/cars/s/" method="get">
<select name="q">
{% for info in modelinfos %}
<option value="{{info.model}}">{{info.model}}</option>
{% endfor %}
</select>
</form>
You are filtering on the forward relationship, so you use the actual field you have defined, model.
CarInfo.objects.filter(model__model__contains=q)
def testform(request):
form = CarInfo(request.POST or None)
if form.is_valid():
save_it = form.save(commit = False)
save_it.save()
return render_to_response("productions/testform.html",locals(),context_instance = RequestContext(request))
Im following the Django docs in order to build a multiple search criteria form. My first question is if this should be the correct method of filtering values in the query and also how can i add the foreignkeys and m2m displayed as selects and multipleselects in the search criteria.. This is my code so far. Thanks
Forms
class SearchPropertyForm(forms.Form):
name = forms.CharField(max_length = 100, widget = forms.TextInput(attrs = {'class':'form-control', 'placeholder':'Nombre'}))
activity = forms.ModelChoiceField(queryset = Activity.objects.all(), widget = forms.Select(attrs = {'class':'form-control', 'placeholder':'Actividad'}))
currency = forms.ModelChoiceField(queryset = Currency.objects.all(), widget = forms.Select(attrs = {'class':'form-control', 'placeholder':'Moneda'}))
price_from = forms.IntegerField(widget = forms.TextInput(attrs = {'class':'form-control', 'placeholder':'Precio-Desde'}))
price_to = forms.IntegerField(widget = forms.TextInput(attrs = {'class':'form-control', 'placeholder':'Precio-Hasta'}))
categories = forms.ModelMultipleChoiceField(queryset = Category.objects.all(), widget = forms.SelectMultiple(attrs = {'class':'form-control', 'placeholder':'Categorias'}))
Model
class Property(models.Model):
class Meta:
verbose_name_plural = "properties"
name = models.CharField(max_length = 200)
description = models.TextField(max_length = 500)
address = models.CharField(max_length = 200)
sqft = models.DecimalField(max_digits = 6, decimal_places = 2)
beds = models.IntegerField()
baths = models.IntegerField()
status = models.BooleanField(default = True)
price = models.DecimalField(max_digits = 6, decimal_places = 2)
likes = models.IntegerField()
categories = models.ManyToManyField(Category, null = True, blank = True)
currency_type = models.ForeignKey(Currency)
activity_type = models.ForeignKey(Activity)
creation_date = models.DateTimeField(auto_now_add = True)
edition_date = models.DateTimeField(default = timezone.now)
def __unicode__(self):
return self.name
View
def search_properties(request):
if request.method == 'POST':
form = SearchPropertyForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
activity = form.cleaned_data['activity']
currency = form.cleaned_data['currency']
price_from = form.cleaned_data['price_from']
price_to = form.cleaned_data['price_to']
categories = form.cleaned_data['categories']
properties = Property.objects.filter(name__icontains = name).filter(
activity_type__exact = int(activity)).filter(
currency_type__exact = int(currency)).filter(
price_from__gte = int(price_from)).filter(
price_from__lte = int(price_to)).filter(
categories__exact = int(categories))
return render(request, 'properties/search_properties.html', {
'properties': properties,
'media_url': settings.MEDIA_URL,
'form':form,
})
else:
form = SearchPropertyForm()
properties = Property.objects.filter(status = True)
return render(request, 'properties/search_properties.html', {
'properties': properties,
'media_url': settings.MEDIA_URL,
'form':form,
})
You can use the Q object in case you are trying to do a or query.
https://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects
so your code could be like this.
from django.db.models import Q
properties = Property.objects.filter(Q(name__icontains = name)|
Q(activity_type__exact = int(activity))|
Q(currency_type__exact = int(currency))|
Q(price_from__gte = int(price_from))|
Q(price_from__lte = int(price_to))|
Q(categories__exact = int(categories))
In the Q object | (pipe) represents an or query and & represents an and query.
So this will return if any of the query is matched.
For the forms section I use Modelform like the following which automatically takes the foreign keys and the multiselects.
class SearchPropertyForm(forms.ModelForm):
class Meta:
model = Property
fields = ('name', 'activity','currency', 'price_form')
You can use Q objects, or simply use django-filter:
Django-filter provides a simple way to filter down a queryset based on parameters a user provides.
Once you have it installed, create a forms.py (since a filter is a type of form), and inside it add the following:
import django_filters
from .models import Property
class PropertyFilter(django_filters.FilterSet):
class Meta:
model = Property
Then, you have to wire it up from your views.py:
from .forms import PropertyFilter
def search(request):
f = PropertyFilter(request.GET, Property.objects.all())
return render(request, 'search.html', {'filter': f})
Your template search.html:
<form method="GET" role="form">
{{ f.form }}
<input type="submit" />
</form>
{% if f|length %}
{% for obj in f %}
{{ obj }}
{% endfor %}
{% else %}
Sorry, no results for your search criteria
{% endif %}
I've 4 models that I need to store data at once. For that I'm thinking using ModelForms.
I've tested with 2 ModelForm's at the same time but it is not working. Here is the code.
Model:
class Main(models.Model):
section = models.ForeignKey(Section)
user = models.ForeignKey(User)
title = models.CharField(max_length=250)
date_inserted = models.DateTimeField(auto_now_add=True)
date_last_update = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.title
# To order in the admin by name of the section
class Meta:
ordering = ['date_inserted']
class BicycleAd(models.Model):
main = models.ForeignKey(Main)
bicycleadtype = models.ForeignKey(BicycleAdType)
bicycleaditemkind = models.ForeignKey(BicycleAdItemKind) # MPTT Model
bicycleadcondition = models.ForeignKey(BicycleAdCondition)
country = models.ForeignKey(GeonamesCountry)
city = models.ForeignKey(GeonamesLocal)
date_inserted = models.DateTimeField(auto_now_add=True)
date_last_update = models.DateTimeField(auto_now=True)
# To order in the admin by name of the section
class Meta:
ordering = ['date_inserted']
Forms:
class MainForm(forms.ModelForm):
class Meta:
model = Main
exclude = ('user', 'section')
class BicycleAdForm(forms.ModelForm):
class Meta:
model = BicycleAd
exclude = ('main', 'bicycleadtype', 'bicycleaditemkind', 'bicycleadcondition', 'city')
View:
def submit_data_entry_view(request):
form_main = MainForm(request.POST)
form_bicyclead = BicycleAdForm(request.POST)
return render_to_response('app/submit_data_entry.html', {'form_main': form_main, 'form_bicyclead': form_bicyclead}, context_instance=RequestContext(request))
Template:
<form method="post" action="">
{{form_main}}
{{form_bicyclead}}
</form>
At the end I only get the"form_bicyclead" outputed in the browser? How can I get the two forms at once?
Best Regards,
are you using submit_data_entry_view to render forms too? shouldn't it be like -
def submit_data_entry_view(request):
if request.method == 'POST': #form submit
form_main = MainForm(request.POST)
form_bicyclead = BicycleAdForm(request.POST)
#now process and save the form
return <whatever_you_want>
elif request.method == 'GET': #first time rendering the form
form_main = MainForm()
form_bicyclead = BicycleAdForm()
return render_to_response('app/submit_data_entry.html', {'form_main': form_main, 'form_bicyclead': form_bicyclead}, context_instance=RequestContext(request))