I'm trying to make this work, with no success so far.
I'm using Django 1.6.5 and mongoengine 0.8.7.
I have some ReferenceField field types in my models.py, which I need to show in a Choice Field type, into a forms.py file.
So, these choices must be filled with the queryset from the referenced (or related models). So when I for example choose to register something in my app, I can relate for example 'users' to 'brands' or 'causes', etc...
Anyways, this was a brief explanation of what I'm trying to achieve with my app, here's my models.py:
from mongoengine import *
class Brand(DynamicDocument):
name = StringField(min_length=3,max_length=10,unique=True)
admins = ListField(ReferenceField("Peer", dbref=True))
campaigns = ListField(ReferenceField("Campaign"))
peers_partner = ListField(ReferenceField("Peer"))
payments = ListField(ReferenceField("Payment_Campaign"))
medias = ListField(EmbeddedDocumentField("Media"))
description = StringField(min_length=10,max_length=500)
socials = ListField(DictField())
def __unicode__(self):
return self.name
#property
def pic_profile(self):
for x in self.medias:
if x.tag == "profile":
return x.url
#property
def pic_banner(self):
for x in self.medias:
if x.tag == "banner":
return x.url
#property
def video_profile(self):
for x in self.medias:
if x.tag == "video":
return x.url
As you can see, there are some ReferenceField fields on my class, these are relationships with other models, but I'm still stuck trying to populate a choice field from forms.py with these references, here's my forms.py:
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Fieldset, ButtonHolder, Submit, Field, Div
from bson.objectid import ObjectId
from mongoengine.queryset import Q
from mongoengine import *
from hdb.brand.models import *
class Form_save_brand(forms.Form):
name = forms.CharField()
admins = forms.ModelChoiceField(queryset=Brand.objects.get_or_create(id=Peer),empty_label="")
campaigns = forms.ChoiceField()
peers_partner = forms.ChoiceField()
payments = forms.ChoiceField()
medias = forms.ChoiceField()
socials = forms.ChoiceField()
def __init__(self, *args, **kwargs):
self.instance = kwargs.pop('instance', None)
super(Form_save_brand, self).__init__(*args, **kwargs)
if self.instance:
self.fields['name'].initial = self.instance.name
self.fields['admins'].initial = self.instance.admins
self.fields['campaigns'].initial = self.instance.campaigns
self.fields['peers_partner'].initial = self.instance.peers_partner
self.fields['payments'].initial = self.instance.payments
self.fields['medias'].initial = self.instance.medias
self.fields['socials'].initial = self.instance.socials
def save(self, commit=True):
brand = self.instance if self.instance else Brand()
brand.name = self.cleaned_data['name']
brand.admins = self.cleaned_data['admins']
brand.campaigns = self['campaigns']
brand.peers_partner = self.cleaned_data['peers_partner']
brand.payments = self.cleaned_data['payments']
brand.medias = self.cleaned_data['medias']
brand.socials = self.cleaned_data['socials']
if commit:
brand.save()
return brand
The only field where I'm doing tests it's the fisrt ReferenceField (admins), which is where I'm stuck, if I manage to solve this I can continue with the other ones.
This is the traceback from Django:
NameError at /brand/nuevo/
name 'Peer' is not defined
Request Method: GET
Request URL: http://localhost:9000/brand/nuevo/
Django Version: 1.6.5
Exception Type: NameError
Exception Value:
name 'Peer' is not defined
Exception Location: /home/kkoci/hipeers/hweb/hweb/hweb/brand/forms.py in Form_save_brand, line 11
Python Executable: /home/kkoci/hipeers/hweb/hipeersweb/bin/python
As you can see right now the query it's like (id=Peer) but I've tried with (id=field), (id=name), etc... with no luck.
I hope I've explained myself...
Any ideas?
Any help would be greatly appreciated, please I'm stuck with this.
Thanks in advance!
EDIT
This is how I initiliaze the form in views.py:
class AddBrand(CreateView):
model = Brand
form_class = Form_save_brand
def get_template_names(self):
return ["brand/brand_nuevo.html"]
def get_success_url(self):
return reverse('list')
def brand_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
messages.success(self.request, "The brand has been created.")
return super(AddBrand, self).brand_valid(form)
Then in template brand/brand_nuevo.html:
{% extends "base.html" %}
{% block body %}
<form action="." method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit"/>
</form>
{% endblock body %}
So, what you need is to instantiate the Form_save_brand with a specific peer so you can work out the dependencies and what is shown. This can be achieved by this (most of the code is kept the same)
You have to change the form to the following:
class Form_save_brand(forms.Form):
name = forms.CharField()
campaigns = forms.ChoiceField()
peers_partner = forms.ChoiceField()
payments = forms.ChoiceField()
medias = forms.ChoiceField()
socials = forms.ChoiceField()
def __init__(self, peer, *args, **kwargs):
# we pass a peer parameter that will be used in the queryset query
self.instance = kwargs.pop('instance', None)
self.fields['admins'] = forms.ModelChoiceField(queryset=Brand.objects.get_or_create(id=peer),empty_label="")
and then, on your view
class AddBrand(CreateView):
model = Brand
# you don't need a form class here
def get_form(self, form_class=None):
return Form_save_brand(<you set the peer value here>, **self.get-form_kwargs())
Related
I'm facing with a validation form problem.
I have this model:
class Documenti(models.Model):
descr = models.CharField('descrizione ', max_length=200)
data = models.DateField('data', blank=True)
objects = models.Manager()
class Meta:
verbose_name = 'Documenti'
this is the form:
class DocForm(ModelForm):
def __init__(self, *args, **kwargs):
super(DocForm, self).__init__(*args, **kwargs)
class Meta:
model = Documenti
exclude = ['id']
widgets = {
'data': forms.DateInput(format=FORMATO_INPUT_DATE, attrs={'type': 'date', 'class': 'stdh-data'}),
'descr': forms.TextInput(attrs={SIZE: '80'}),
}
and this is the edit function:
def edit_doc(request, doc_id=None):
"""
:param request:
:param doc_id:
"""
if not (doc_id is None):
doc_that = get_object_or_404(Documenti.objects.all(), pk=doc_id)
titolo = ED_DOCUMENTO
else:
doc_that = Documenti()
titolo = INS_DOCUMENTO
form = DocForm(request.POST or None, instance=doc_that)
redirect_to = Documenti().get_absolute_url() + current_page(request)
if form.is_valid(): # All validation rules pass
doc = form.save(commit=False)
doc.save()
return HttpResponseRedirect(redirect_to) # Redirect after POST
else:
print(form)
from documenti.urls import url_views_lista_doc
url_after_close = full_url(request, 'doc:%s' % url_views_lista_doc)
dizio = {FORM: form, TitleScheda: titolo, TAG_url_after_close: url_after_close, }
return generic_render(request, HTML_generic_edit, dizio)
I always get FALSE when I check form.is_valid().
I tried to get error list with {{ form.non_field_errors }} {{ form.field_errors }}
but they seems void.
No idea.
many thanks in advance
I solved!
I had a dot in my action form.
e.g. form name='x' method='POST' action='.'
I remeved that malefic dot (action='') and TADA!!! it works
don't ask me why!
I am new to django, and I am creating a vacation application. I want to be able to when I create a new trip, the user that created the trip becomes a member of that trip.
here is my models.py file:
class Trip(models.Model):
trip_name = models.CharField(max_length=255,unique=False)
start_date = models.DateField(default=datetime.date.today)
end_date = models.DateField(default=datetime.date.today)
slug = models.SlugField(allow_unicode=True,unique=True)
members = models.ManyToManyField(User,through='TripMember')
def __str__(self):
return self.trip_name
def save(self,*args,**kwargs):
self.slug = slugify(self.trip_name)
super().save(*args,**kwargs)
def get_absolute_url(self):
return reverse('trips:single',kwargs={'slug':self.slug})
class Meta:
ordering = ['start_date']
class TripMember(models.Model):
trip = models.ForeignKey(Trip,null=True,related_name='memberships',on_delete=models.SET_NULL)
user = models.ForeignKey(User,null=True,related_name='user_trips',on_delete=models.SET_NULL)
def __str__(self):
return self.user.username
class Meta:
unique_together = ('trip','user')
this is my forms.py file:
class TripCreateForm(forms.ModelForm):
class Meta:
fields = ('trip_name','start_date','end_date')
model = Trip
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["trip_name"].label = "Trip Name"
self.fields["start_date"].label = "Start Date"
self.fields["end_date"].label = "End Date"
here is my views.py file:
class CreateTrip(CreateView):
form_class = TripCreateForm
template_name = 'trips/trip_form.html'
and my trip_form.html page:
<form action="{% url 'trips:create' %}" method="post" id='tripForm'>
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-primary btn-large" value="Create">
</form>
Where would I put the code to set the user as a tripmember and why?Also, if there is a better way to have set this up please let me know! I was gonna put it in the save part of the model but I am not quite sure if that is correct. Thanks!
You can override the form_valid() method of the CreateTrip class in your view:
def form_valid(self, form):
"""If the form is valid, save the associated model."""
self.object = form.save()
# add the current user to the members list of the trip
user = self.request.user
self.object.members.add(user)
return super().form_valid(form)
When submitting the button after clicking like it is creating the object successufuly but like field is updating with null value and django is getting error 302. Can somebody please help me with this.
After Edit
I have removed form_valid function from the SongVoteUpdateView now update part is working fine but if I removed form_valid function from SongVoteCreatView It is throwing intigrity error like this NOT NULL constraint failed: album_vote.song_id. For trace back please refer this link, if not removed it will creat blank object with no like.
models.py
Codes in models.py
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(null=True, blank=True, 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}) #'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 SongVoteCreateView(CreateView):
form_class = SongVoteForm
model = Vote
def get_success_url(self,**kwargs):
song_id = self.kwargs.get('song_id')
return reverse('music:song_detail', kwargs={'pk':song_id})
def form_valid(self, form):
user = self.request.user
song_obj = Song.objects.get(pk=self.kwargs['song_id'])
vote_obj, created = Vote.objects.get_or_create(song = song_obj, user = user)
form.instance = vote_obj
return super(SongVoteCreateView).form_valid(form)
class SongUpdateVoteView(UpdateView):
form_class = SongVoteForm
model = Vote
# def form_valid(self, form):
# user = self.request.user
# song_obj = Song.objects.get(pk=self.kwargs['song_id'])
# vote_obj, created = Vote.objects.get_or_create(song = song_obj, user = user)
# form.instance = vote_obj
# print(form)
# return super().form_valid(form)
def get_success_url(self):
song_id = self.kwargs.get('song_id')
return reverse('music:song_detail', kwargs={'pk':song_id})
urls.py
url mapping
path('album/song/<int:pk>/',views.SongDetailView.as_view(), name='song_detail'),
path('album/song/create/<int:song_id>/',views.SongVoteCreateView.as_view(), name='song_vote_create'),
path('album/song/update/<int:song_id>/<int:pk>/', views.SongUpdateView.as_view(), name='song_vote_update')
song_detail.html
Codes in html page
<div>
<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>
</div>
forms.py
Code in forms.py
class SongVoteForm(forms.ModelForm):
like = forms.ChoiceField(widget=forms.RadioSelect,choices=Vote.VALUE_CHOICE)
class Meta:
model = Vote
fields = ['like',]
error Code
response got in console.
[31/Oct/2019 04:15:19] "GET /album/song/1/ HTTP/1.1" 200 3560
**[31/Oct/2019 04:15:21] "POST /album/song/update/1/8/ HTTP/1.1" 302 0**
[31/Oct/2019 04:15:21] "GET /album/song/1/ HTTP/1.1" 200 3560
I have explicitly mentioned like in the form_valid in SongVoteCreateView as shown below. Now the form is not creating blank object and redirecting to the correct page.
def form_valid(self, form):
like = form.cleaned_data.get('like')
user = self.request.user
song_obj = Song.objects.get(pk=self.kwargs['song_id'])
vote_obj, created = Vote.objects.get_or_create(song = song_obj, user = user, like=like)
form.instance = vote_obj
return super().form_valid(form)
I try to find the best way to have a field with multiple content types.
What I've done so far is a Contact model with a contacttype CharField:
class Contact(models.Model):
CONTACT_TYPES = (
('email', 'Email'),
('phone', 'Phone'),
('address', 'Address'),
('facebook', 'Facebook'),
('linkedin', 'LinkedIn'),
('youtube', 'Youtube'),
('twitter', 'Twitter'),
('google', 'Google'),
)
teammember = models.ForeignKey(TeamMember)
description = models.CharField(max_length=100, null=True)
contacttype = models.CharField(max_length=100, choices= CONTACT_TYPES, default='email')
contact = models.TextField()
My goal is to let the user add different contact informations, which'll be listed on the profile page, but with only one model.
I was thinking about a class for each ModelForm:
class ContactForm(ModelForm):
def __init__(self, data, *args, **kwargs):
super(ModelForm, self).__init__(data, *args, **kwargs)
self.contacttype = ""
class Meta:
model = Contact
fields = ['description', 'contact']
widgets = {'contact': TextInput()}
def clean_contacttype(self):
return self.contacttype
class ContactEmailForm(ContactForm):
def __init__(self, data, *args, **kwargs):
super(ContactForm, self).__init__(data, *args, **kwargs)
self.contacttype = "email"
class Meta(ContactForm.Meta):
model = Contact
fields = ['description', 'contact']
widgets = {'contact': EmailInput()}
class ContactPhoneForm(ContactForm):
def __init__(self, data, *args, **kwargs):
super(ContactForm, self).__init__(data, *args, **kwargs)
self.contacttype = "phone"
class Meta(ContactForm.Meta):
model = Contact
fields = ['description', 'contact']
widgets = {'contact': TextInput()}
def clean_contact(self):
cleaned_data = super(ContactForm, self).clean()
contact = cleaned_data.get("contact")
# Perform some phone number validations
return contact
Then, in my view, I would choose the correct form depending on the request argument (ex: /contact/add/email or /contact/add/phone).
I'm trying to find the most elegant way to do this, so any help is welcome.
Thanks for reading.
if you want to use one html file, then this is one of solutions.
class YourView(TemplateView):
template_name = 'your_template.html'
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
if context['type'] == 'phone':
context['form'] = ContactPhoneForm
elif ...
if you set your view, then
<form action="{% url "your view" %}" enctype="multipart/form-data" method="POST">{% csrf_token %}
{% if form.contenttype == 'phone' %}
{% include "partials/contact_phone_form.html" with form=form %}
{% elif form.contenttype == 'email' %}
{% include "partials/contact_email_form.html" with form=form %}
{% else %}
do something.
{% endif %}
</form>
and, contact_phone_form.html and contact_email_form is looks like
anything.
<input name='phone'>
anything.
this solution is for one template, multi form.
if you want to do multi template for specific form, then you can use this.
class YourView(TemplateView):
template_name = 'your_template.html'
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
if context['type'] == 'phone':
template_name = 'phone_form_template.html'
elif context['type'] == 'email':
template_name = 'email_form_template.html'
...
I would use forms.Form depending on the request argument like:
/contact/add/?type=email or /contact/add/?type=phone
and so you can use it like (not tested code):
class ContactForm(forms.Form):
def __init__(self, *args, **kwargs):
super(CreateUserquestionnaireForm, self).__init__(*args, **kwargs)
if "email" in self.data:
... do some thing like change contact type or widget
if "phone" in self.data:
... do some thing like change contact type or widget
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()