I have app in Django 1.8 and I want to take last object (based on pub_date) and set for this object filed is_mainteaser on True and rest ssould be set on False.
Here is my code, but latest object hasn't field set to True.
class ArticleListView(ListView):
model = Article
queryset = Article.objects.order_by('-pub_date')
def get_context_data(self, **kwargs):
context = super(ArticleListView, self).get_context_data(**kwargs)
lates_object = Article.objects.latest('pub_date')
lates_object.is_mainteaser = True
return context
Here is my model:
class Article(model.Models):
title = models.CharField(max_length=255)
short_text = models.TextField(max_length=10000, default='')
image = FilerImageField(null=True)
pub_date = models.DateTimeField('date published')
online_from = models.DateTimeField('online from', blank=True)
online_to = models.DateTimeField('online to', blank=True)
position = models.PositiveIntegerField(default=0)
is_mainteaser = models.BooleanField(default=False)
def __str__(self):
return self.title
class Meta:
ordering = ['position']
When you have object instance and change model attribute you must save instance. Example:
lates_object = Article.objects.latest('pub_date')
lates_object.is_mainteaser = True
lates_object.save()
I think better for this solution is use django signals or action when you add new article. In ListView is't good solution to do it that.
Related
I am using a Detail View generic and I am trying to add an attribute to each item for a group of Comments (The detail view is for a Post that has many comments). I am trying to loop through the group of comments and assign a boolean to a new attribute is_liked_by_user. When I try to print comment.is_liked_by_user it will show in the scope of it but when I try to find it in the context['post'] I get this error *** AttributeError: 'Comment' object has no attribute 'is_liked_by_user'. What is the correct way to assign this attribute so that it can be passed to my template?
class DetailView(LoginRequiredMixin,generic.DetailView):
model = Post
template_name = 'posts/detail.html'
form_class = CommentsForm
def get_context_data(self, **kwargs):
# Call the base implementation first to get the context
context = super(DetailView, self).get_context_data(**kwargs)
# Create any data and add it to the context
context['form'] = self.form_class
post = context['post']
comments = post.comment_set.all()
for i, comment in enumerate(comments):
comment.is_liked_by_user = check_existing_dictionary_in_list(comment.reactions.all(), "user", self.request.user)
print("Was comment liked by user?", comment.is_liked_by_user, comment.comment_body)
# comment.is_liked_by_user = check_existing_dictionary_in_list(comment.reactions.all(), "user", self.request.user)
# context['is_liked_by_user'] = check_existing_dictionary_in_list(post.reactions.all(), "user", self.request.user)
pdb.set_trace()
return context
class Comment(models.Model):
comment_body = models.CharField(max_length=200)
like_count = models.IntegerField(default=0)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
author = models.ForeignKey(User, on_delete=models.CASCADE, null = True)
created_date = models.DateTimeField('date created', null=True, auto_now_add=True,blank=True )
reactions = GenericRelation(Reaction)
def __str__(self):
return self.comment_body
So i have this two models in django:
class Course(models.Model):
def get_image_path(self, filename):
return os.path.join('courses', str(self.slug), filename)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Course, self).save(*args, **kwargs)
name = models.CharField(max_length=255, verbose_name="Nombre")
description = models.CharField(max_length=255, verbose_name="DescripciĆ³n")
price = models.DecimalField(max_digits=12,decimal_places=2, verbose_name="Precio")
slug = models.SlugField(blank=True, max_length=255)
icon_img = models.ImageField(upload_to=get_image_path, blank=True, null=True, verbose_name="Imagen")
background_color = ColorField(default="#026085")
class Meta:
verbose_name = "curso"
verbose_name_plural = "cursos"
class UserCourse(models.Model):
user = models.ForeignKey(User)
course = models.ForeignKey(Course)
So whenever a user "buys" a course, it is stored in UserCourse. I have a view where the system shows a list of all the courses the user has bought. This is the view code:
def user_course_list_view(request, username):
context_dict = {}
try:
user_courses = UserCourse.objects.filter(user=request.user).course_set
context_dict['courses'] = user_courses
context_dict['heading'] = "Mis cursos"
except:
context_dict['courses'] = None
context_dict['heading'] = "Mis cursos wey"
return render(request, 'courses/course_list.html', context=context_dict)
I dont know where is the error and I cant seem to catch the exception (im using django with docker)
tl;dr
Something like this should work.
usercourse_objects = UserCourse.objects.filter(user=request.user).select_related('course')
user_courses = [x.course for x in usercourse_objects]
Explanation
There are multiple ways to do this, but one way would be to first get all the UserCourse objects for the current user:
usercourse_objects = UserCourse.objects.filter(user=request.user)
Then, for each UserCourse object, get the related Course:
user_courses = [x.course for x in usercourse_objects]
Now, the second line causes N database queries (one for each time we follow the course foreign key relation. To prevent this, the first line can be changed to:
usercourse_objects = UserCourse.objects.filter(user=request.user).select_related('course')
This pre-populates the course attribute of the UserCourse objects. More info about select_related() can be found here.
I have a linked model:
class Children(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
child_name = models.CharField(max_length=150, null=True, blank=True)
slug = AutoSlugField(populate_from='child_name')
blood_group = models.CharField(max_length=5, blank=True)
class Meta:
unique_together = ('slug', 'person')
def get_absolute_url(self):
return self.person.get_absolute_url()
def get_delete_url(self):
return reverse(
'member:children-delete',
kwargs={
'person_slug': self.person.slug,
'children_slug': self.slug})
def get_update_url(self):
return reverse(
'member:children-update',
kwargs={
'person_slug': self.person.slug,
'children_slug': self.slug})
my forms.py:
class ChildrenForm( SlugCleanMixin, forms.ModelForm):
class Meta:
model = Children
exclude = ('person',)
def clean(self):
cleaned_data = super().clean()
slug = cleaned_data.get('slug')
person_obj = self.data.get('person')
exists = (
Children.objects.filter(
slug__iexact=slug,
person=person_obj,
).exists())
if exists:
raise ValidationError(
"Children with this Slug "
"and Person already exists.")
else:
return cleaned_data
def save(self, **kwargs):
instance = super().save(commit=False)
instance.person = (
self.data.get('person'))
instance.save()
self.save_m2m()
return instance
views.py:
class ChildrenCreate( ChildrenFormMixin, ChildrenGetObjectMixin,
PersonContextMixin,CreateView):
template_name = 'member/children_form.html'
model = Children
form_class = ChildrenForm
class ChildrenUpdate(ChildrenFormMixin, ChildrenGetObjectMixin,
PersonContextMixin,UpdateView):
template_name = 'member/children_form.html'
model = Children
form_class = ChildrenForm
slug_url_kwarg = 'children_slug'
class ChildrenDelete(ChildrenFormMixin,ChildrenGetObjectMixin,
PersonContextMixin,DeleteView):
model = Children
slug_url_kwarg = 'children_slug'
def get_success_url(self):
return (self.object.person
.get_absolute_url())
my utils.py:
class ChildrenFormMixin():
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
if self.request.method in ('POST', 'PUT'):
self.person = get_object_or_404(
Person,
slug__iexact=self.kwargs.get(
self.person_slug_url_kwarg))
data = kwargs['data'].copy()
data.update({'person': self.person})
kwargs['data'] = data
return kwargs
class ChildrenGetObjectMixin():
def get_object(self, queryset=None):
person_slug = self.kwargs.get(
self.person_slug_url_kwarg)
children_slug = self.kwargs.get(
self.slug_url_kwarg)
return get_object_or_404(
Children,
slug__iexact=children_slug,
person__slug__iexact=person_slug)
class PersonContextMixin():
person_slug_url_kwarg = 'person_slug'
person_context_object_name = 'person'
def get_context_data(self, **kwargs):
person_slug = self.kwargs.get(
self.person_slug_url_kwarg)
person = get_object_or_404(
Person, slug__iexact=person_slug)
context = {
self.person_context_object_name:
person,
}
context.update(kwargs)
return super().get_context_data(**context)
The children created more than one for same name of same parents. When I tried to edit children it gives "get() returned more than one Children -- it returned 2!" error. In traceback, it said, 'person__slug__iexact=person_slug' is the direct causes of this traceback.
In the form, I added clean method to catch the error and maintain uniqueness of children name of same parents but it not worked. Could I get suggestions where I do wrong?
Edit:
my Person model:
class Person(models.Model):
name = models.CharField(max_length=250)
slug = AutoSlugField(populate_from='name')
birth_date = models.DateField(null=True, blank=True)
blood_group = models.CharField(max_length=5)
present_address = models.CharField(max_length=250, blank=True)
permanent_address = models.CharField(max_length=250, blank=True)
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
related_name='member_persons')
class Meta:
ordering = ['name']
unique_together = ['name', 'birth_date']
I believe you are using AutoSlugField from django-autoslug, and you trying to get by non-unique field. AutoSlugField won't make your field unique by default, from docs:
AutoSlugField can also perform the following tasks on save:
populate itself from another field (using populate_from),
use custom slugify function (using slugify or Settings), and
preserve uniqueness of the value (using unique or unique_with).
None of the tasks is mandatory, i.e. you can have auto-populated non-unique fields, manually entered unique ones (absolutely unique or within a given date) or both.
So quick fix would be slug = AutoSlugField(populate_from='child_name', unique=True)
UPDATE(Since you posted your Person model)
The problem is the same and solution is the same.
Explanation:
For example you have two Person objects:
id name slug birth_date
1 alex alex 10.10.2016
2 alex alex 10.10.2015
This won't violate unique_together = ['name', 'birth_date']
And you got two Children objects:
id name slug person_id
1 john john 1
2 john john 2
And that won't violate unique_together = ('slug', 'person') neither
Then you are making query
get_object_or_404(
Children,
slug__iexact='john',
person__slug__iexact='alex')
Which would match two objects. So you got problem. Quick fix would be to make slug unique=True.
It's a sort of cms type application
I have an article model and some specializations in models.py
class Article(models.Model):
foo = models.CharField(max_length=50)
bar = models.CharField(max_length=100,blank=True)
DISPLAY_CHOICES = (
('N', 'None'),
('C','Carousel'),
('M','Marketing'),
('F','Featurette')
)
display = models.CharField(max_length=1, choices = DISPLAY_CHOICES)
def __unicode__(self):
return self.title
class Artist(Article):
website = models.URLField(max_length=200,blank=True)
class Venue(Article):
location = models.CharField(max_length=150)
map_link = models.URLField(max_length=200,blank=True)
class Event(Article):
time = models.DateTimeField()
venue = models.ForeignKey(Venue)
performers = models.ManyToManyField(Artist)
I want to render these in different ways depending on the value of article.display but when I call
articles.objects.all()
I still need the extra attributes form the subclasses so I wrote
#views.py
def castToSubClass(article):
try:
return Artist.objects.get(article_ptr_id = article.id)
except:
try:
return Event.objects.get(article_ptr_id = article.id)
except:
try:
return Venue.objects.get(article_ptr_id = article.id)
except:
return article
def index(request):
carousel = [castToSubClass(article) for article in Article.objects.filter(display='C']
marketing = [castToSubClass(article) for article in Article.objects.filter(display='M'[:3]]
featurettes = [castToSubClass(article) for article in Article.objects.filter(display='F']
return render_to_response('frontpage.html',
{
'carousel': carousel,
'marketing':marketing,
'featurettes': featurettes
})
to turn them all in the appropriate subclass object, this apart from seeming clunky seems to mean I'm hitting the database twice for every (or nearly every) item in the queryset.
Is there a way to do this in the initial calls to the manager instead?
Thanks.
Use one model to store everything, and add a field to distinguish the article type, so that you can render different look for every type combine with display in the template(Like tumblr do).
class Article(models.Model):
foo = models.CharField(max_length=50)
bar = models.CharField(max_length=100,blank=True)
DISPLAY_CHOICES = (
('N', 'None'),
('C','Carousel'),
('M','Marketing'),
('F','Featurette')
)
display = models.CharField(max_length=1, choices = DISPLAY_CHOICES)
ARTICLE_TYPE_CHOICES = (
('artist', 'Artist'),
('venue', 'Venue'),
('event', 'Event'),
)
type = models.CharField(max_length=32, choices = ARTICLE_TYPE_CHOICES)
website = models.URLField(max_length=200,blank=True, null=True)
location = models.CharField(max_length=150, blank=True, null=True)
map_link = models.URLField(max_length=200,blank=True, null=True)
time = models.DateTimeField(null=True)
venue = models.ForeignKey('self', null=True)
performers = models.ManyToManyField('self', null=True)
def __unicode__(self):
return self.title
#views.py
def index(request):
carousel = Article.objects.filter(display='C')
marketing = Article.objects.filter(display='M')
featurettes = Article.objects.filter(display='F')
return render_to_response('frontpage.html',{'carousel': carousel, 'marketing':marketing, 'featurettes': featurettes})
I'm trying to save some form data inputted by the user. I would like to slugify the "name" which was entered by the user, but dont want the slug field to show on the template that the user sees. I tried to do it manually with the sell function that you see below, but cant quite get it to work. I want to eventually save the slugified name into the Item model I have listed below. I'm sure there's a much smarter/simpler way than the sell function I'm currently using :P. Thanks in advance!
class Item(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=75)
slug = models.SlugField(max_length=50, unique=True)
is_active = models.BooleanField(default=True)
image = models.CharField(max_length=50)
price = models.DecimalField(max_digits=9, decimal_places=2)
quantity = models.IntegerField(default=1)
description = models.TextField()
created = models.DateTimeField(auto_now_add=True)
shipping_price = models.DecimalField(decimal_places=2, max_digits=6)
categories = models.ManyToManyField(Category)
class AddItem(forms.ModelForm):
class Meta:
model = Item
exclude = ('user','slug','is_active',)
def sell(request):
if request.method == "POST":
form = AddItem(request.POST)
item = form.save(commit=False)
item.user = request.user
item.is_active = True
item.slug = slugify(form.name) **#not sure what this line should be?**
item.save()
if form.is_valid():
form.save()
return HttpResponseRedirect('thanks.html')
else:
url = urlresolvers.reverse('register')
return HttpResponseRedirect(url)
You can exclude slug from user form.
And slugify in pre_save signal.
from django.dispatch import receiver
from django.db.models.signals import pre_save
#receiver(pre_save, sender=Item)
def iter_pre_save_handler(sender, instance, **kwargs):
if not instance.pk:
instance.slug = slugify(instance.name)
According to the docs, you can exclude a field from being rendered in a model form like this:
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'title')
or
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
exclude = ('birth_date',)
or by setting editable=False on the Field instance in your model.
Once you have done this, you can override the save method of the model, as the comments in the OP have suggested:
# shamelessly copied from http://stackoverflow.com/questions/837828/how-do-i-create-a-slug-in-django/837835#837835
from django.template.defaultfilters import slugify
class test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField()
def save(self, *args, **kwargs):
self.s = slugify(self.q)
super(test, self).save(*args, **kwargs)