Django methodSerializer doesnt return absolute image url - django

Serializer.py
class PostImageSerializer(serializers.ModelSerializer):
class Meta:
model = PostImage
fields = ('id', 'post', 'post_img')
class PostSerializer(serializers.ModelSerializer):
postimg_set = serializers.SerializerMethodField('get_postimg_set')
editor = UserSerializer()
class Meta:
model = Post
fields = ('id', 'title', 'content', 'editor', 'postimg_set', 'created_at')
def get_postimg_set(self, obj):
a = PostImage.objects.filter(post = obj.id)
print(a[0].post_img)
return PostImageSerializer(a, many=True).data
models.py
from django.db import models
import os, uuid, datetime
from apps.account.models import *
from django.utils import timezone
def img_upload(instance, filename):
ext = filename.split('.')[-1]
now = datetime.datetime.now()
path = "media/static/post/{}".format(instance.post.id)
format = uuid.uuid4().hex + "_" + filename
return os.path.join(path, format)
class Post(models.Model):
title = models.CharField('제목', null=False, blank=False, max_length=40)
content = models.TextField('내용', null=False, blank=False)
editor = models.ForeignKey(User, default = 1, null=False, blank=False, verbose_name="작성자", on_delete=models.CASCADE)
created_at = models.DateTimeField(default=timezone.localtime())
class Meta:
verbose_name = '게시글'
verbose_name_plural = '게시글'
def __str__(self):
return self.title
class PostImage(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
post_img = models.ImageField(upload_to=img_upload)
class Meta:
verbose_name = "게시글 이미지"
verbose_name_plural = "게시글 이미지"
def __str__(self):
return str(self.post.title) + "이미지"
Guess postimg_set = serializers.SerializerMethodField('get_postimg_set') is not return absolute URL for the images. When I use UserSerializer(), it returned absolute image url of User's profile image.
Looking for help. Thank you

In your urls.py, Add:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
-- closed--

Related

Django Modelform user issues

I have a model form to list an item and I am trying to get the form to fill in the user id from the user that is submitting the form. Currently, the form is submitted successfully but it always uses the first user in the database's id for every item.
models.py
class Item(models.Model):
id = models.UUIDField( primary_key=True, default=uuid.uuid4, editable=False )
creator = models.ForeignKey( get_user_model(), on_delete=models.CASCADE, default=2)
item_name = models.CharField(max_length=40)
price = models.DecimalField(max_digits = 6, decimal_places=2)
description = models.CharField(max_length= 500)
main_image = models.ImageField(upload_to=path_and_rename , max_length=255, null=True, blank=True)
image_2 = models.ImageField(upload_to='items/', blank=True)
image_3= models.ImageField(upload_to='items/', blank=True)
image_4= models.ImageField(upload_to='items/', blank=True)
image_5= models.ImageField(upload_to='items/', blank=True)
quantity = models.IntegerField(default=1, validators=[ MaxValueValidator(100),MinValueValidator(1)])
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
def __str__(self):
return self.item_name
def get_absolute_url(self):
return reverse("item_detail_view", args=[str(self.id)])
forms.py
from django.forms import ModelForm, forms
from .models import Item
class List_Item_Form(ModelForm):
forms.ModelChoiceField(queryset=Item.objects.filter(user=user))
class Meta:
model = Item
def __init__(self, *args, **kwargs):
user = kwargs.pop("user", None)
super().__init__(*args, **kwargs)
views.py
class AddListing( generic.CreateView):
template_name = 'store/add_listing.html'
fields = ('item_name','price','description','main_image','quantity')
model = Item
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
It can be done using function based view too because there we get current user more easily.
Try this:
models.py
from django.db import models
from django.contrib.auth.models import User
class Item(models.Model):
creator = models.ForeignKey(User, on_delete=models.CASCADE)
item_name = models.CharField(max_length=40)
price = models.DecimalField(max_digits=6, decimal_places=2)
description = models.CharField(max_length=500)
main_image = models.ImageField(
upload_to=path_and_rename, max_length=255, null=True, blank=True)
image_2 = models.ImageField(upload_to='items/', blank=True)
image_3 = models.ImageField(upload_to='items/', blank=True)
image_4 = models.ImageField(upload_to='items/', blank=True)
image_5 = models.ImageField(upload_to='items/', blank=True)
quantity = models.PositiveIntegerField(default=1)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
def __str__(self):
return self.item_name
admin.py
from django.contrib import admin
from home.models import Item
#admin.register(Item)
class ItemRegister(admin.ModelAdmin):
lis_display = ['id', 'creator', 'item_name', 'price', 'description']
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.list, name='home'),
path('success/', views.success, name='success')
]
forms.py
from django.forms import ModelForm, forms
from .models import Item
class ListItemForm(ModelForm):
class Meta:
model = Item
fields = ['item_name', 'price', 'main_image'
'description', 'quantity']
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .models import Item
from .forms import ListItemForm
def list(request):
if request.method == 'POST':
form = ListItemForm(request.POST)
if form.is_valid():
itemName = form.cleaned_data['item_name']
price = form.cleaned_data['price']
desc = form.cleaned_data['description']
quan = form.cleaned_data['quantity']
main_img = form.cleaned_data['main_image']
current_user = request.user
model_instance = Item(creator=current_user, item_name=itemName, price=price,
description=desc, quantity=quan, main_image=main_img)
model_instance.save()
return HttpResponseRedirect('/success/')
else:
form = ListItemForm()
return render(request, 'store/add_listing.html', {'form': form})
def success(request):
return render(request, 'store/success.html')
Rest of the fields of models you can customize very easily in the view.

Django admin page with summer note editor causing toggle to expand making it look odd

I currently installed django summer note on a blog. It loads fine, and I see no errors in console, but it looks like this ..
The main admin loads fine, it's just the create post page.
My admin.py file in the blog looks like this
from django.contrib import admin
from .models import Post, Newsletter
from django_summernote.admin import SummernoteModelAdmin
class PostAdmin(SummernoteModelAdmin):
list_display = ('title', 'slug', 'status', 'created_on')
list_filter = ('status', 'created_on')
search_fields = ['title', 'content']
prepopulated_fields = {'slug': ('title',)}
summernote_fields = ('content',)
admin.site.register(Post, PostAdmin)
class NewsletterAdmin(admin.ModelAdmin):
list_display = ('email', 'confirmed')
admin.site.register(Newsletter, NewsletterAdmin)
And the post models are
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
STATUS = (
(0,"Draft"),
(1,"Publish")
)
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="blog_posts"
)
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ["-created_on"]
def __str__(self):
return self.title
def get_absolute_url(self):
from django.urls import reverse
return reverse("post_detail", kwargs={"slug": str(self.slug)})
class Newsletter(models.Model):
email = models.EmailField(null=False, blank=True, max_length=200, unique=True)
conf_num = models.CharField(max_length=15)
confirmed = models.BooleanField(default=False)
def __str__(self):
return self.email + " (" + ("not " if not self.confirmed else "") + "confirmed)"
For some reason my admin CSS wasn't fully copied. So make sure when you collect static that you pass it to the static if you are using nginx correctly.

How to use detailview pk in createview

# models.py
class NewBlank(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=50)
description = models.CharField(max_length=100, blank=True)
blank_on_off = models.BooleanField(default=False)
create_date = models.DateTimeField(auto_now_add=True)
update_date = models.DateTimeField(auto_now=True)
class BlankContent(models.Model):
refer = models.TextField()
memo = models.TextField()
new_blank = models.ForeignKey('NewBlank', on_delete=models.CASCADE, related_name='blankcontent')
# views.py
class BlankDetail(LoginRequiredMixin, DetailView):
model = NewBlank
template_name = 'blank_app/blank_detail.html'
context_object_name = 'blank'
class BlankContentCreate(CreateView):
model = BlankContent
fields = "__all__"
template_name = 'blank_app/new_blank_content_create.html'
def get_success_url(self):
return reverse_lazy('blank_detail', kwargs={'pk': self.object.new_blank.pk})
# urls.py
urlpatterns = [
path('blank/<int:pk>/', BlankDetail.as_view(), name='blank_detail'),
path('new-blank-content/', BlankContentCreate.as_view(), name='blank_content_create'),
]
There is a creativeview in the detail view and I want to create a model in the detailview when I press it. So even if I don't specify the new_blank part, I want it to be filled automatically according to the pk in the detailview, what should I do?
In case you want to perform some extra work in your DetailView, one of the ways to do that would be to override the get_object method.
from django.views.generic import DetailView
class BlankDetail(LoginRequiredMixin, DetailView):
model = NewBlank
template_name = 'blank_app/blank_detail.html'
context_object_name = 'blank'
def get_object(self):
obj = super().get_object()
# do your thing with obj.pk
pk = self.kwargs.get('pk') # in case you want to access the `pk` from URL

Save Django Form wizard data to three models with related fields

I am working on a project that requires use of form wizard to populate three related models. The first model - Listing - has general data which has a OneToOneField relationship with the second model (Property). The Listing model also has a many to many relationships with the third model (ListingImages). In general, I am using 4 forms in the wizard. Here is the models definition
models.py
class Listing(models.Model):
listing_type_choices = [('P', 'Property'), ('V', 'Vehicle'), ('B', 'Business/Service'), ('E', 'Events')]
listing_title = models.CharField(max_length=255)
listing_type = models.CharField(choices=listing_type_choices, max_length=1, default='P')
status = models.BooleanField(default=False)
featured = models.BooleanField(default=False)
city = models.CharField(max_length=255, blank=True)
location = PlainLocationField(based_fields=['city'], zoom=7, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
expires_on = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User,
on_delete=models.CASCADE, editable=False, null=True, blank=True
)
listing_owner = models.ForeignKey(User,
on_delete=models.CASCADE, related_name='list_owner'
)
def __str__(self):
return self.listing_title
def get_image_filename(instance, filename):
title = instance.listing.listing_title
slug = slugify(title)
return "listings_pics/%s-%s" % (slug, filename)
class ListingImages(models.Model):
listing = models.ForeignKey(Listing, on_delete=models.CASCADE)
image_url = models.ImageField(upload_to=get_image_filename,
verbose_name='Listing Images')
main_image = models.BooleanField(default=False)
class Meta:
verbose_name_plural = "Listing Images"
def __str__(self):
return f'{self.listing.listing_title} Image'
class Property(models.Model):
sale_hire_choices = [('S', 'Sale'), ('R', 'Rent')]
fully_furnished_choices = [('Y', 'Yes'), ('N', 'No')]
listing = models.OneToOneField(Listing, on_delete=models.CASCADE)
sub_category = models.ForeignKey(PropertySubCategory, on_delete=models.CASCADE)
for_sale_rent = models.CharField(choices=sale_hire_choices, max_length=1, default=None)
bedrooms = models.PositiveIntegerField(default=0)
bathrooms = models.PositiveIntegerField(default=0)
rooms = models.PositiveIntegerField(default=0)
land_size = models.DecimalField(max_digits=10, decimal_places=2)
available_from = models.DateField()
car_spaces = models.PositiveIntegerField(default=0)
fully_furnished = models.CharField(choices=fully_furnished_choices, max_length=1, default=None)
desc = models.TextField()
property_features = models.ManyToManyField(PropertyFeatures)
price = models.DecimalField(max_digits=15, decimal_places=2)
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Here is the forms.py
from django import forms
from .models import Listing, Property, Vehicle, Business, ListingImages
from django.forms import modelformset_factory
class ListingDetails(forms.ModelForm):
class Meta:
model = Listing
fields = ['listing_title', 'city', 'location']
class PropertyDetails1(forms.ModelForm):
class Meta:
model = Property
fields = ['sub_category', 'for_sale_rent', 'bedrooms', 'bathrooms',
'rooms', 'land_size', 'available_from', 'car_spaces', 'fully_furnished',
'desc', 'currency', 'price'
]
class PropertyDetails2(forms.ModelForm):
class Meta:
model = Property
fields = ['property_features']
class ListingImagesForm(forms.ModelForm):
image_url = forms.ImageField(label='Listing Image',
widget=forms.ClearableFileInput(attrs={'multiple': True}),
required=False
)
class Meta:
model = ListingImages
fields = ['image_url']
ImageFormSet = modelformset_factory(ListingImages, form=ListingImagesForm, extra=3)
views.py
from django.shortcuts import render, redirect
import os
from .forms import ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm
from .models import ListingImages, Listing, Property
from formtools.wizard.views import SessionWizardView
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.forms import modelformset_factory
from django.contrib import messages
from django.http import HttpResponseRedirect, HttpResponse
from django.forms.models import construct_instance
class PropertyView(SessionWizardView):
# formset = ImageFormSet(queryset=Images.objects.none())
template_name = "listings/create_property.html"
form_list = [ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm]
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'media'))
def done(self, form_list, **kwargs):
listing_instance = Listing()
property_instance = Property()
listing_instance.created_by = self.request.user
listing_instance.listing_owner = self.request.user
listing_instance.listing_type = 'P'
for form in form_list:
listing_instance = construct_instance(form, listing_instance, form._meta.fields, form._meta.exclude)
property_instance = construct_instance(form, property_instance, form._meta.fields, form._meta.exclude)
listing = listing_instance.save()
property_instance.listing = listing
property_instance.save()
return HttpResponse('data saved successfully')
The problem that I am facing is that I am able to save the Listing model, but getting its primary id and using it to save the Property model is the problem. Again, the ListingImages model stores images related to the Listing model. How do I save these models to database considering that they are multiple?
What's wrong is that as described here, model.save() does not return the saved object, but None.
So the last few lines of the above code should be
listing_instance.save()
property_instance.listing = listing_instance
property_instance.save()
return HttpResponse('data saved successfully')
Ditto saving a set of listing_images would be something like
for li_obj in listing_image_instances:
li_obj.listing = listing_instance # saved above
li_obj.save()

How to fix django admin "add" button

I'm new to web development, and i'm building a blog web app in Django.
I'm having problems adding new posts through django-admin. Clicking the "add" button gives me an "Error during template rendering - 'str' object has no attribute 'utcoffset'" error message.
models.py
from django.db import models
from django.utils import timezone
import datetime
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=50)
content = models.TextField(blank=True, null=True)
post_date = models.DateTimeField(default='date posted')
def published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.post_date <= now
published_recently.admin_order_field = 'post_date'
published_recently.boolean = True
published_recently.short_description = 'Recent post?'
def __str__(self):
return self.title
class Customer(models.Model):
username = models.CharField(max_length=50)
firstname = models.CharField(max_length=50)
lastname = models.CharField(max_length=50)
email = models.CharField(max_length=50)
country = models.CharField(max_length=50)
reg_date = models.DateTimeField(default='date reg')
def __str__(self):
return self.username
class Comment(models.Model):
comment_cont = models.TextField(max_length=200)
user_name = models.ForeignKey(Customer, default=0, on_delete=models.CASCADE)
comment_post = models.ForeignKey(Post, on_delete=models.CASCADE)
votes = models.BigIntegerField(default=0)
comment_date = models.DateTimeField(default='date commented')
def __str__(self):
return self.comment_cont
class Feedback(models.Model):
feedback_title = models.CharField(max_length=50)
feedback_detail = models.CharField(max_length=200)
user_name = models.ForeignKey(Customer, default=1, verbose_name='user_name', on_delete=models.SET_DEFAULT)
admin.py
from django.contrib import admin
from .models import Post, Customer, Feedback, Comment
# Register your models here.
class CommentInLine(admin.TabularInline):
model = Comment
extra = 1
fields = ['comment_cont', 'votes', 'comment_date']
class CustomerAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['firstname', 'lastname', 'username', 'email', 'country', 'reg_date']})
]
class PostAdmin(admin.ModelAdmin):
fieldsets = [
('Post', {'fields': ['title', 'content']}),
('Date information', {'fields': ['post_date'], 'classes':['collapse']}),
]
inlines = [CommentInLine]
list_display = ('title', 'content', 'post_date', 'published_recently')
list_filter = ['post_date']
search_fields = ['title']
class FeedbackAdmin(admin.ModelAdmin):
fieldsets = [
('Feedback', {'fields': ['feedback_title', 'feedback_detail', 'user_name']}),
]
list_display = ('user_name', 'feedback_title', 'feedback_detail')
# inlines = [CustomerInLine]
# list_display = ('user_name', 'feedback_title', 'feedback_detail')
class CommentAdmin(admin.ModelAdmin):
fields = ['user_name', 'comment_post', 'comment_cont', 'votes', 'comment_date']
admin.site.register(Post, PostAdmin)
admin.site.register(Feedback, FeedbackAdmin)
admin.site.register(Customer, CustomerAdmin)
admin.site.register(Comment, CommentAdmin)
I want to be able to add posts through Django admin. Any other corrections to the code is highly welcome. I appreciate the help. Thanks.
post_date = models.DateTimeField(default='date posted')
the post_date is DateTimeField and you have provided a string as default . It should be an instance of datetime.datetime.
post_date = models.DateTimeField(default=timezone.now)
# or
post_date = models.DateTimeField(auto_now_add=True, verbose_name='Publish Time')
should fix the problem