I have two models and two different forms. Tow forms are combined in a single view function. The two forms are combined in a single HTML form. Everything is working fine when I submit the HTML form except the images are not saved.
Here are the tow models:
class Posts(models.Model):
user = models.ForeignKey(MyUser, on_delete=models.CASCADE)
post_category = models.ForeignKey(Post_Category,
on_delete=models.CASCADE)
post_title = models.CharField(max_length=256)
post_detail = models.TextField(max_length=65536)
def __str__(self):
return "%s %s %s %s " % (
self.user, self.post_category, self.post_title,
self.post_detail)
class Meta:
verbose_name_plural = "Posts"
class Images(models.Model):
post = models.ForeignKey(Posts, on_delete=models.CASCADE)
images = models.ImageField(upload_to='images', blank=True, null=True )
def __str__(self):
return "%s %s" % (self.post, self.images)
class Meta:
verbose_name_plural = "images"
the forms are:
class PostsForm(forms.ModelForm):
class Meta:
model = Posts
fields = [
'post_category',
'post_title', 'post_detail',
]
class ImagesForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
kwargs.setdefault('label_suffix', '')
super(ImagesForm , self).__init__(*args, **kwargs)
self.fields['car_images'].widget.attrs.update({'class' : 'image',
'style':'display:none','id':'input-image-hidden',
'onchange':"document.getElementById('image-preview').src = window.URL.createObjectURL(this.files[0])" ,
'type':'file', "name":"images", 'accept':'image/*'})
class Meta:
model = Images
fields = [
'images',
]
widgets = {
'images': forms.ClearableFileInput(attrs={'multiple': True}),
}
Here is the view function:
from django.forms import inlineformset_factory
from django.utils.translation import ugettext_lazy as _
def post(request):
form = PostsForm()
imagesForm = ImagesForm()
template_name = 'path/to/template.html'
success_url = 'user_profile.html'
form = PostsForm(request.POST or None)
imagesForm = ImagesForm(request.POST or None,
request.FILES or None)
if form.is_valid() and imagesForm.is_valid():
new_post = form.save(commit=False)
new_post.user = request.user
new_post = form.save()
imagesForm.save(commit=False)
for file in request.FILES.getlist('images'):
instance = Images(
post= Posts.objects.get("images"),
images=file
)
instance.save()
return redirect('index')
else:
imagesForm = ImagesForm(request.POST or None, request.FILES or
None)
return render(request, template_name, {'imagesForm': imagesForm,
'form': form})
When the HTML form is submitted, all data are saved except the images( no error pups up).the HTML form is displayed again rather than redirect to the user profile page.
Can you please advise me to what is going on and where is the possible error or errors. Can you help me to save multiple images
NOTE: USING inline formset factory is not possible if I have to set extra parameter. I do not want to limit user to upload limited numbers of images.
Related
I have a filter in django rest charfilterinfilter(field_name= 'genres__name', lookup_expr= 'in').I have in the database is which two categories to approach I through Many To Many did ,But I have when filtrating two categories of this product there are two elements I need only one element
views
class CharFilterInFilter(filters.BaseInFilter, filters.CharFilter):
pass
class ShoppFilter(filters.FilterSet):
price = filters.RangeFilter()
genres = CharFilterInFilter(field_name='genres__name')
title = SearchFilter()
class Meta:
model = smartphone
fields = ['price','genres','title']
class MDShopListView(generics.ListAPIView):
queryset = smartphone.objects.all()
filter_backends = (DjangoFilterBackend,SearchFilter)
search_fields = ['title']
filterset_class = ShoppFilter
def get(self, request):
queryset = self.filter_queryset(self.get_queryset())
serializer=MDShopListSerializer(queryset,many=True)
return Response(serializer.data)
models
genres = models.ManyToManyField(Genre, verbose_name="жанры")
class Genre(models.Model):
[enter image description here][1]
name = models.CharField("Имя", max_length=100)
img json
1: https://i.stack.imgur.com/4WR6L.png
here change and work
queryset = self.filter_queryset(self.get_queryset()).distinct()
class CharFilterInFilter(filters.BaseInFilter, filters.CharFilter):
pass
class ShoppFilter(filters.FilterSet):
price = filters.RangeFilter()
genres = CharFilterInFilter(field_name='genres__name', lookup_expr='in')
title = SearchFilter()
class Meta:
model = smartphone
fields = ['price','genres','title']
class MDShopListView(generics.ListAPIView):
queryset = smartphone.objects.all()
filter_backends = (DjangoFilterBackend,SearchFilter)
search_fields = ['title']
filterset_class = ShoppFilter
def get(self, request):
queryset = self.filter_queryset(self.get_queryset()).distinct()
serializer=MDShopListSerializer(queryset,many=True)
return Response(serializer.data)
This is a usual problem with ManyToMany fields, solution would be to apply a distinct method to the query:
class ShoppFilter(filters.FilterSet):
...your filter definition as it is now
def filter_queryset(self, request, queryset, view):
return super(ShoppFilter, self).filter_queryset(
request, queryset, view
).distinct()
I am using the YouTube Data API to create an object, but when I create a single object, it creates two objects - one with the proper details and one that is blank. How can I resolve this issue?
before creating object
after creating single object
I am trying with the following code.
view.py
class VideoCreateView(CreateView):
model = Video
form_class = VideoForm
template_name = "videos/video_form.html"
def form_valid(self, form):
video = Video()
video.url = form.cleaned_data['url']
parse = urllib.parse.urlparse(video.url)
video_id = urllib.parse.parse_qs(parse.query).get('v')
if video_id:
video.youtube_id =video_id[0]
response = requests.get(f'https://youtube.googleapis.com/youtube/v3/videos?part=snippet&id={video_id[0]}&key={YOUTUBE_API_KEY}')
json = response.json()
items = json["items"]
assert len(items) <= 1
if len(items):
title = items[0]["snippet"]["title"]
video.title = title
video.save()
else:
title = "N/A"
return super().form_valid(form)
models.py
class Video(models.Model):
title = models.CharField(max_length=255)
url = models.URLField()
youtube_id = models.CharField(max_length=255)
slug = models.SlugField(blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("videos:video_detail", kwargs={"slug":self.slug})
def video_pre_save_reciever(sender,instance,*args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(video_pre_save_reciever,Video)
if more code is require than tell me in comment , i will update my question with that information.
The view VideoCreateView inherits CreateView. CreateView inherits ModelFormMixin which defines form_valid method.
def form_valid(self, form):
"""If the form is valid, save the associated model."""
self.object = form.save()
return super().form_valid(form)
You save the video object and call the super form_valid which saves the form(in turn creating a model object) again. Hence, causing a double creation. I suggest modifying the form and passing it to super instead of manually saving it.
Another option is to inherit the View with django.views.generic.View. This would avoid form save.
I suggest you follow the first approach.
I have solve this my problem by removing all the form_valid code from the views and add that inside the model
class Video(models.Model):
title = models.CharField(max_length=255)
url = models.URLField()
youtube_id = models.CharField(max_length=255)
slug = models.SlugField(blank=True)
def save(self,*args,**kwargs):
parse = urllib.parse.urlparse(self.url)
video_id = urllib.parse.parse_qs(parse.query).get('v')
if video_id:
self.youtube_id =video_id[0]
response = requests.get(f'https://youtube.googleapis.com/youtube/v3/videos?part=snippet&id={video_id[0]}&key={YOUTUBE_API_KEY}')
json = response.json()
title = json["items"][0]["snippet"]["title"]
self.title = title
super(Video,self).save(*args,**kwargs)
I am having trouble combining information from my two django models to create a third model in django. In the code provided below I use ProfileFeedItem and UserProfile model to populate a new model. I want this model to keep track of the UserProfiles that are attending specific ProfileFeedItem(these are individual events). I've tried using the EventAttendee model for but it does not work. How should I edit the EventAtendee model to take the event ID and user profile ID form the other models mentioned and associate them with each other in this model.
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.models import BaseUserManager
from django.conf import settings
# Create your models here.
class UserProfileManager(BaseUserManager):
"""Manager for user profiles"""
def create_user(self, email, name, password=None):
"""create a new user profile"""
if not email:
raise ValueError('User must have an email address')
email = self.normalize_email(email)
user = self.model(email=email, name=name)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, name, password):
"""Create and save a new superuser with given details"""
user = self.create_user(email, name, password)
user.is_superuser = True
user.is_staff = True
user.save(using=self._db)
return user
class UserProfile(AbstractBaseUser, PermissionsMixin):
"""Database models for users in the system"""
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserProfileManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def get_full_name(self):
"""retrieve full name of user"""
return self.name
def get_short_name(self):
"""Retrieve short name of user"""
return self.name
def __str__(self):
"""Return string representation of our user"""
return self.email
class ProfileFeedItem(models.Model):
"""Profile status update"""
#below connects user profile to event
user_profile = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
id = models.AutoField(primary_key=True)
poi = models.CharField(max_length=85, blank=True, null=True)
address = models.CharField(max_length=85, blank=True, null=True)
start_time = models.DateTimeField(blank=True, null=True)
end_time = models.DateTimeField(blank=True, null=True)
created_on = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.poi
class EventAtendee(models.Model):
"""Lists users atending an event"""
#below connects user profile to event
id = models.AutoField(primary_key=True)
event_id = models.ForeignKey(
'ProfileFeedItem',
on_delete=models.CASCADE
)
user_profile = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
def __str__(self):
return self.event_id
serializers.py
from rest_framework import serializers
from profiles_api import models
class UserProfileSerializer(serializers.ModelSerializer):
"""Serializes a user profile object"""
class Meta:
model = models.UserProfile
fields = ('id', 'email','name','password')
extra_kwargs = {
'password': {
'write_only': True,
'style': {'input_type':'password'}
}
}
def update(self, instance, validated_data):
"""Handle updating user account"""
if 'password' in validated_data:
password = validated_data.pop('password')
instance.set_password(password)
return super().update(instance, validated_data)
def create(self, validated_data):
"""Create and return a new user"""
user = models.UserProfile.objects.create_user(
email=validated_data['email'],
name=validated_data['name'],
password=validated_data['password']
)
return user
class ProfileFeedItemSerializer(serializers.ModelSerializer):
"""Serializes profile feed items"""
class Meta:
model = models.ProfileFeedItem
fields = ('id', 'user_profile', 'poi', 'address','start_time', 'end_time', 'created_on')
extra_kwargs = {'user_profile': {'read_only': True}}
class EventAtendeeSerializer(serializers.ModelSerializer):
"""Serializes profile feed items"""
class Meta:
model = models.ProfileFeedItem
fields = ('id','event_id', 'user_profile')
extra_kwargs = {'event_id':{'read_only':True},'user_profile': {'read_only': True}}
Your models look fine, but your EventAtendeeSerializer.Meta.model is referencing the wrong model.
Try this:
class EventAtendeeSerializer(serializers.ModelSerializer):
"""Serializes which profiles are attending an event"""
class Meta:
model = models.EventAtendee # this line has changed
fields = ('id', 'event_id', 'user_profile')
extra_kwargs = {'event_id': {'read_only':True}, 'user_profile': {'read_only': True}}
How can i use my custom form called PayForm inside a template (Post.html) which is the template of a view called Post I tried to point both of the views to the same template but as i was told you can't point two views to the same template so i am currently stuck on this
models.py
from django.db import models
from django.urls import reverse
from PIL import Image
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, unique=True)
created = models.DateTimeField(auto_now_add=True)
content = models.TextField(default="---")
current_price = models.IntegerField(default=0)
reduction = models.IntegerField(default=0)
original_price = models.IntegerField(default=0)
Status = models.CharField(max_length=5, default="✓")
img = models.CharField(max_length=255)
sold = models.IntegerField(default=0)
endday = models.CharField(max_length=30, default="apr 27, 2018 16:09:00")
class Meta:
ordering = ['-created']
def __unicode__(self):
return u'%s'% self.title
def get_absolute_url(self):
return reverse('Products.views.post', args=[self.slug])
def __str__(self):
return self.title
class Payment(models.Model):
Author = models.CharField(max_length=255)
Product = models.CharField(max_length=255)
Payment_ID = models.CharField(max_length=255)
Status = models.CharField(max_length=5, default="X")
Review_result = models.CharField(max_length=255, default="Not yet reviewed")
Address = models.CharField(max_length=255, default='')
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created']
def __unicode__(self):
return u'%s'% self.Status
def __str__(self):
return self.Status
views.py
from django.shortcuts import render, render_to_response , get_object_or_404, redirect
from .models import Post
from django.contrib.auth import authenticate, login, logout
from .forms import RegistrationForm, PayForm
def index(request):
posts=Post.objects.all()
return render(request, 'Index.html', {"posts": posts})
def post(request, slug):
return render(request, 'post.html', {'post': get_object_or_404(Post, slug=slug)})
def new_payment(request):
template ='payment.html'
if request.method == 'POST':
form = PayForm(request.POST)
if form.is_valid():
form.save()
return redirect('index')
else:
print('form invalid')
else:
form = PayForm({'Author':request.user.username})
context = {
'form' : form,
}
return render(request, template, context)
forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Payment, Post
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = User
fields = (
'username',
'first_name',
'last_name',
'email',
'password1',
'password2',
)
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
class PayForm(forms.ModelForm):
class Meta:
model = Payment
fields = ['Author', 'Product', 'Payment_ID', 'Address']
If someone can help me with this it would be greatly appreciated
If you have already created new_payment_form.html(or whatever you have called it) you can simply add to the post.html by using the {% include %} tag surrounded with appropriate <form> tags and whatever you need to go with it. The {% include %} essentially copies and pastes all the code from whatever file you have inside the tag. And a general rule, Product means class and product means variable or field.
# new_payment_form.html is the name of your html file.
# template_path is the directory to your template.
<form>
{% include 'template_path/new_payment_form.html' %}
<button> # submit button
</form>
However, you still need to process it in the view.
def post(request, slug):
"""
(all the if: else: stuff)
"""
# Set new_payment product
new_payment = PayForm(initial={'Product': slug})
return render(request, 'post.html', {'post': get_object_or_404(Post, slug=slug), 'new_payment': new_payment})
You will probably rewrite your view, and there are some details to figure out, but that should get you headed in the right direction. You might want to change slug to a product id or pk.
I want to POST a message to the Message table in my db, which contains the following fields:
id;
body;
normaluser;
chat.html:
<form method="post" id="msg">
<div class="form-group">
<label for="comment">Message:</label>
<textarea class="form-control" rows="5" id="comment"></textarea>
</div>
{% csrf_token %} {{ form.as_p }}
<button type="submit">Enter</button>
</form>
views.py
#login_required
def msg(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
body = form.cleaned_data.get('body')
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
Message(request, user)
else:
form = 'msg'
args = {'form': form}
return render(request, 'accounts/chat.html', args)
class MessageListView(APIView):
def get(self, request): # lista objectos
serializer = MessageSerializer(instance=Message.objects.all(), many=True)
return Response(serializer.data)
def post(self, request): # cria objecto
serializer = MessageSerializer(data=request.data, many=False)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
models.py
class Message(models.Model):
body = models.CharField(max_length=500)
normaluser = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.body
serializer.py
class MessageSerializer(serializers.ModelSerializer):
normaluser = MessageUserSerializer(many=False, read_only=True)
class Meta:
model = Message
fields = ('id', 'body', 'normaluser')
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email')
I am basing my view from the def I use to make a new user. But I'm not understanding how to change it to accept a message, which also receives the info of the user authenticated at the time he sends the message. I am using the django User table to create users and login.
The Django user creation form is for creating a user. You basically want to customise this to add an extra message field and save this as a related object. Your form should be something like this (not had a chance to test it):
class UserCreateWithMessageForm(UserCreationForm):
message = forms.TextField()
def save(self, #args, **kwargs):
user = super(UserCreateWithMessageForm, self).save()
message_txt = self.cleaned_data['message']
Message.objects.create(body=message_txt, normaluser=user)
return user