I'm trying to use Django's ModelForm and inline forms in my templates. However, I cannot find any documentation that maps neatly to a database model with multiple foreign keys back to the same table. These are my models:
# models.py
class Universities(models.Model):
name = models.CharField(max_length=100)
class Majors(models.Model):
name = models.CharField(max_length=80)
class Resumes(models.Model):
name = models.CharField(max_length=70)
undergrad = models.ForeignKey(Universities, related_name='undergrad_university')
undergrad_major = models.ForeignKey(Majors, related_name='undergrad_major')
grad = models.ForeignKey(Universities, related_name='grad_university')
grad_major = models.ForeignKey(Majors, related_name='grad_major')
How can I have Django generate a form for submitting Resumes where users can type in their university name and major? All four of which would be used to create new entries in their respective databases (2 in Universities, 2 in Majors) before saving the new resume similar to how the inline formset example works for a singular foreign key.
EDIT2 : For making a form. I guess I'd have done a personalized form with overriding of save() method, something like this (forms.py):
class YourForm(forms.Form):
fname = forms.CharField(label="name",max_length=70,validators=[#Choose your validators here])
fundergrad = forms.CharField(label="fundergrad",max_length=100,validators=[#Choose your validators here])
fundergrad_major = forms.CharField(label="fundergrad_major",max_length=80,validators=[#Choose your validators here])
fgrad = forms.CharField(label="fgrad",max_length=100,validators=[#Choose your validators here])
fgrad_major = forms.CharField(label="fgrad_major",max_length=80,validators=[#Choose your validators here])
def save(self, datas):
res = Resumes()
res.name = datas['fname']
undergrad = Universities()
undergrad_major = Majors()
grad = Universities()
grad_major = Majors()
undergrad.name = datas['fundergrad']
undegrad_major.name = datas['fundergrad_major']
grad.name = datas['fgrad']
grad_major.name = datas['fgrad_major']
undergrad.save()
undergrad_major.save()
grad.save()
grad_major.save()
res.undergrad = undergrad
res.undergrad_major = undergrad_major
res.grad = grad
res.grad_major = grad_major
res.save()
return res
In views.py :
def formView(request) :
if request.method == 'POST':
form = YourForm(request.POST)
if form.is_valid():
datas={}
datas['fundergrad']=form.cleaned_data['fundergrad']
datas['fundergrad_major']=form.cleaned_data['fundergrad_major']
datas['fgrad']=form.cleaned_data['fgrad']
datas['fgrad_major']=form.cleaned_data['fgrad_major']
form.save(datas)
#Then do what you have to do in your view
EDIT1 : (doesn't answer the question, but it could help someone maybe so I let it here)
I would have tried with something like this in admin.py:
class UniversitiesInline1(admin.StackedInline):
model = Universities
fk_name = "undergrad"
class UniversitiesInline2(admin.StackedInline):
model = Universities
fk_name = "grad"
class MajorsInline1(admin.StackedInline):
model = Majors
fk_name = "undergrad_major"
class MajorsInline2(admin.StackedInline):
model = Majors
fk_name = "grad_major"
class ResumesAdmin(admin.ModelAdmin)
inlines = [
UniversitiesInline1,
UniversitiesInline2,
MajorsInline1,
MajorsInline2,
]
admin.site.register(Resumes, ResumesAdmin)
Explanations : https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-a-model-with-two-or-more-foreign-keys-to-the-same-parent-model
Related
How can I serialize related objects in DRF. Am having three models auth_user (User), ModelA, ModelB.
My models:
class ModelA(models.Model):
user = models.OneToOneField(auth_user, related_name = 'modelA')
name = models.CharField(max_length = 30)
class ModelB(models.Model):
owner = models.OneToOneField(auth_user)
user = models.OneToOneField(auth_user, related_name = 'modelB')
type = models.ForeignKey(ModelD)
cost = models.IntegerField()
class ModelD(models.Model):
type_desc = models.CharField(max_length = 40)
My serialilzers:
class A(serializers.ModelSerializer):
class Meta:
model = ModelA
fields = ('name', )
class B(serializers.ModelSerializer):
class Meta:
model = ModelB
fields = ('type', 'cost', )
class AuthUserSerilaizer(serializers.ModelSerializer):
userA = serializers.RelatedField(source = 'modelA')
userB = serializers.RelatedField(source = 'modelB')
class Meta:
model = User
fields = ('email', 'password', 'userA', 'userB', )
write_only_fields = ('password',)
#transaction.commit_manually
def restore_object(self, attrs, instance = None):
try:
user = User.objects.create_user(email = attrs.get('email'), password = attrs.get('password'))
modela = ModelA(user =user, name = attrs.get('name'))
modela.save()
transaction.commit()
return User(email = attrs.get('email'))
except Exception ,e:
transaction.rollback()
print repr(e)
JSON I'm passing
data = {'email':'123#gmail.com,
'password' : 'dummy',
'userA' : {'name' :'123'},
'userB':{'type':1,'cost':'100'}
Whenever am making a POST request the 'attrs' gets only email and password not userA and userB, why? How can I deserialize and create data serially in the respective tables.
try this in your view
from django.core.serializers.json import DjangoJSONEncoder
import json
response = json.dumps(data,cls=DjangoJSONEncoder)
return HttpResponse(response, mimetype="application/json")
and in success function you can access using
usera_name = response.userA.name
userb_type = response.userB.type
userb_cost = response.userB.cost
I'm trying to customize and many to many inline in the django Admin, but I'm not able to display the fields of the underlying models.
Here's a simplified example. Maybe you can tell me how to reference them?
Here are my models:
class Clown(models.Model):
name = models.CharField(max_length=255)
def edit_link(self):
return ...
class Circus(models.Model):
clowns = models.ManyToManyField(Clown, blank=True, through='WorkedAt')
name = models.CharField(max_length=255)
class WorkedAt(models.Model):
clown = models.ForeignKey(Clown)
circus = models.ForeignKey(Circus)
and my admin:
class ClownInline(admin.TabularInline):
model = WorkedAt
fields = ['clown__name','clown__edit_link']
class CircusAdmin(admin.ModelAdmin):
inlines = [
ClownInline,
]
exclude = ('clowns',)
However I get this error:
Unknown field(s) (clown__name) specified for WorkedAt
(I'm on Django 1.6)
Update:
Why won't this work either. (Added calculated field to through model.)
class Clown(models.Model):
name = models.CharField(max_length=255)
def edit_link(self):
return ...
class Circus(models.Model):
clowns = models.ManyToManyField(Clown, blank=True, through='WorkedAt')
name = models.CharField(max_length=255)
class WorkedAt(models.Model):
clown = models.ForeignKey(Clown)
circus = models.ForeignKey(Circus)
#property
def edit_link(self):
return self.clown.edit_link()
and my admin:
class ClownInline(admin.TabularInline):
model = WorkedAt
fields = ['edit_link']
class CircusAdmin(admin.ModelAdmin):
inlines = [
ClownInline,
]
exclude = ('clowns',)
Try this. Hope it solves your problem
class ClownInline(admin.TabularInline):
model = WorkedAt
fields = ['clown_name', 'clown_edit_link']
readonly_fields = ['clown_name', 'clown_edit_link']
def clown_name(self, instance):
return instance.clown.name
clown_name.short_description = 'clow name'
def clown_edit_link(self, instance):
url = reverse("admin:%s_%s_change" % (instance.clown._meta.app_label, instance.clown._meta.module_name), args=(instance.clown.pk,))
return '%s' % (url, instance.clown.name)
clown_edit_link.allow_tags = True
class CircusAdmin(admin.ModelAdmin):
inlines = [
ClownInline,
]
exclude = ('clowns',)
I don't know if anyone still needs this, because this question is 4 years old but this solved my problem for in Django 2.0.3:
# models.py
class Clown(models.Model):
name = models.CharField(max_length=255)
def edit_link(self):
return ...
class Circus(models.Model):
clowns = models.ManyToManyField(Clown, blank=True, through='WorkedAt')
name = models.CharField(max_length=255)
class WorkedAt(models.Model):
clown = models.ForeignKey(Clown)
circus = models.ForeignKey(Circus)
# admin.py
class WorkedAtInline(admin.TabularInline):
model = WorkedAt
extra = 1
class WorkedAtAdmin(admin.ModelAdmin):
inlines = (WorkedAtInline,)
admin.site.register(Clown, WorkedAtAdmin)
Hope this helps anyone that stumbles upon this problem and looks into this answer.
I'm saving a form, but there is one save() method that is outside the transaction. The save() method outside a transaction is the save() on the "BicycleAdCategoryForm".
Here is the code:
models.py
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']
class BicycleAdCategoryType(models.Model):
n_bicycle_ad_category_type = models.CharField(max_length=100) # COMPRA, VENDA, TROCA
date_inserted = models.DateTimeField(auto_now_add=True)
date_last_update = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.n_bicycle_ad_category_type
# To order in the admin by name of the section
class Meta:
ordering = ['n_bicycle_ad_category_type']
forms.py
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') # DPS RETIRAR DAQUI A "CITY"
class BicycleAdCategoryForm(forms.ModelForm):
bicycleadcategorytype = forms.ModelMultipleChoiceField(queryset=BicycleAdCategoryType.objects.all(), required=False, widget=forms.CheckboxSelectMultiple) # Se retirar o widget fico uma SELECT box em q posso selecionar varias opcoes
class Meta:
model = BicycleAdCategory
exclude = ('bicyclead',)
def save(self, commit, rel_obj):
data = self.data.getlist('bicycleadcategorytype')
for item in data:
obj_bicycleadcategory = BicycleAdCategory()
obj_bicycleadcategory.bicyclead = rel_obj
obj_bicycleadcategory.bicycleadcategorytype = BicycleAdCategoryType.objects.get(pk=item)
obj_bicycleadcategory.save()
def clean_bicycleadcategorytype(self):
data = self.cleaned_data['bicycleadcategorytype']
try:
for item in data:
bicycleadcategorytype = BicycleAdCategoryType.objects.get(pk=item.pk)
return bicycleadcategorytype
except (KeyError, BicycleAdCategoryType.DoesNotExist):
raise forms.ValidationError('Invalid Bicycle Ad Category Type. Please try again.')
views.py
def submit_ad_view(request):
if request.method == 'POST':
model_main = Main()
model_main.section = Section.objects.get(pk=request.POST['section'])
model_main.user = request.user
model_bicyclead = BicycleAd()
model_bicyclead.bicycleadtype = BicycleAdType.objects.get(pk=2)
model_bicyclead.bicycleaditemkind = BicycleAdItemKind.objects.get(pk=4)
model_bicyclead.bicycleadcondition = BicycleAdCondition.objects.get(pk=2)
model_bicyclead.city = GeonamesLocal.objects.get(pk=4803854)
form_main = MainForm(request.POST, instance = model_main)
form_bicyclead = BicycleAdForm(request.POST, instance = model_bicyclead)
form_bicycleadcategory = BicycleAdCategoryForm(request.POST)
if form_main.is_valid() and form_bicyclead.is_valid() and form_bicycleadcategory.is_valid():
main_f = form_main.save()
bicyclead_f = form_bicyclead.save(commit=False)
bicyclead_f.main = main_f
bicyclead_f.save()
bicycleadcategory_f = form_bicycleadcategory.save(commit=False, rel_obj=model_bicyclead)
resultado = 'valid'
else:
resultado = 'n_valid'
return render_to_response('app/submit_ad.html', {'resultado': resultado}, context_instance=RequestContext(request))
I think main_f and bicyclead_f are inside a transaction but bicycleadcategory_f is outside a transaction. When bicycleadcategory_f fails, main_f and bicyclead_f are stored in the database.
Any clue on what I'm doing wrong?
Best Regards,
Django executes views using the commit_on_success decorator (or at least it behaves that way). If you're view crashes (uncaught exceptions), a rollback should take place. If some data is stored, and some is not there is a possibility that your DB engine does not support transactional processing.
Check out the django doc for more info
https://docs.djangoproject.com/en/dev/ref/databases/
For example, if you're using MySQL with MyISAM you may encounter some problems
edit:
Krzysiek Szularz: I guess everybody is using django TransactionMiddleware or simmilar things, so I skipped it - and mentioned only the logic layer.
I have 1 question.
These are my django models.(This is just example)
class Users(models.Model):
username = models.Charfield()
class CommunityBoard(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=30)
contents = models.TextField()
I send data(nsdictionary format) to server using post
{ pk = 1 }
in views.py
def detailCommuBoard(request):
returnValues = {}
returnValues.update(csrf(request))
pk = request.POST['pk'];
detailContents = CommunityBoard.objects.filter(pk=pk)
returnValues = serializers.serialize('json', detailContents)
return HttpResponse(returnValues)
then, I got serialized data in iphone.(json format)
{
fields = {
contents = "\Uc5ed\Uc2dc \Ud30c\Uc774\Uc36c";
title = "\Ud30c\Uc774\Uc36c \Ud504\Ub85c\Uadf8\Ub798\Ubc0d";
user = 1;
};
pk = 11;
}
I want to show User model's username when make queryset, not user model's pk.
please Help me.
I think you need to change the Queryset to include that information.
detailContents = CommunityBoard.objects.filter(pk=pk).values_list('contents', 'title', 'user__username')
returnValues = serializers.serialize('json', detailContents)
You can make use of natural keys during serialization.
So you can try this:
returnValues = serializers.serialize('json', detailContents,
use_natual_keys=True)
i have the following models
class SchoolClass(models.Model):
id = models.AutoField(primary_key = True)
class_name = models.TextField()
level = models.IntegerField()
taught_by = models.ManyToManyField(User,related_name="teacher_teaching",through='TeachSubject')
attended_by = models.ManyToManyField(User,related_name='student_attending')
def __unicode__(self):
return self.class_name
class Meta:
db_table = 'classes'
class Relationship(models.Model):
rChoices = (
(1,'Mother'),
(2,'Father'),
(3,'Guardian'),
)
parent = models.ForeignKey(User,related_name='parent')
student = models.ForeignKey(User,related_name='child')
relationship = models.IntegerField(choices= rChoices)
#add in __unicode__ for admin name
class Meta:
unique_together = ('parent','student')
db_table = 'relationship
I have the the pk of the class, and I want to find out who are the parents of the students in the selected class.
My feeble attempt is:
selected_class = SchoolClass.objects.get(pk=class_id)
studs = selected_class.attended_by.all().select_related()
r = Relationship.objects.filter(student__in=students)
parents = [.parent for p in r]
Now, I am just curious if there is a shorter or more efficient way of doing this(i'm sure missed something in the docs) ?
This should work
parents = Relationship.objects.filter(student__schoolclass__id=class_id).values_list('parent', flat=True)
"To refer to a "reverse" relationship, just use the lowercase name of the model". (docs)