Pass Two Models to View

pass two models to view

You can create special viewmodel that contains both models:

public class CurrencyAndWeatherViewModel
{
public IEnumerable<Currency> Currencies{get;set;}
public Weather CurrentWeather {get;set;}
}

and pass it to view.

public ActionResult Index(int year,int month,int day)
{
var currencies = from r in _db.Currencies
where r.date == new DateTime(year,month,day)
select r;
var weather = ...

var model = new CurrencyAndWeatherViewModel {Currencies = currencies.ToArray(), CurrentWeather = weather};

return View(model);
}

How to pass two models to one View

Make one class that contains both models

Your first model:

public class ModelOne { ... }

Your second model:

public class ModelTwo { ... }

The model that you pass to your view:

public class UltimateViewModel 
{
public ModelOne One { get; set; }
public ModelTwo Two { get; set; }
}

There is no problem with creating a view model class to encapsulate everything that you want to send to the view. In fact, this would be preferable to doing something like storing one of your models in ViewState, since you can enforce your strong typing in the view, referring to everything using @Model.One or @Model.Two`.

Passing two models in one view

You should create a ViewModel for this, which wraps both Task and AssignedTask objects like this -

public class TaskViewModel
{
public Task Task { get; set; }
public AssignedTask AssignedTask { get; set; }
}

then bind your View with this view model i.e. TaskViewModel for example -

@model MyWebApplication2.Models.TaskViewModel

you will then be able to access the model properties just like any other object. For example to create a text box for TaskName, you could do -

@Html.TextBoxFor(m=>m.Task.TaskName)

Django - Pass two Models into one view, and display both models

The difficulty comes from the fact that you combine a list view and create view. If you want to combine this into one view, then you need to do a bit mixing and matching with different mixins of the Class Based Views.

It can be done, but it's not trivial. If you're new to Django, then this may be overshooting things. I've renamed fields an such and did it as an exercise. I haven't bothered with the form submission, it shouldn't be that difficult to implement as the other views don't deal with the methods involved (form_valid, get_success_url, etc). You can use it as a guide to see what you should be learning. The above linked site is extremely convenient to see how things are mixed together.

The result below will provide the variables "foodtruck", "reviews" and "form" to the template.

import typing as t

from django.views import generic
from .models import FoodTruck, Review
from .forms import ReviewForm

if t.TYPE_CHECKING:
from django.http import HttpRequest, HttpResponse
from django.contrib.auth.models import AbstractUser

class AuthenticatedRequest(HttpRequest):
user: AbstractUser = ...

class FoodTruckDetailReviewListCreateView(
generic.list.MultipleObjectMixin, generic.edit.CreateView,
):
template_name = "foodtrucks/detail.html"
model = Review
list_model = Review
context_list_name = "reviews"
context_object_name = "foodtruck"
detail_model = FoodTruck
form_class = ReviewForm

def get(self, request: "AuthenticatedRequest", *args, **kwargs) -> "HttpResponse":
"""
Combine the work of BaseListView and BaseDetailView

Combines the get implementation of BaseListView and BaseDetailView, but
without the response rendering. Then hands over control to CreateView's
method to do the final rendering.

Some functionality is stripped, because we don't need it.

:param request: The incoming request
:return: A response, which can be a redirect
"""
# BaseListView
self.object_list = self.get_queryset()
# BaseDetailView
self.object = self.get_object()
context = self.get_context_data(
object=self.object, object_list=self.object_list
)
# CreateView sets self.object to None, but we override form_kwargs, so
# we can leave it at a value.

return self.render_to_response(context=context)

def get_template_names(self):
# Bypass logic in superclasses that we don't need
return [self.template_name]

def get_object(self, queryset=None):
# We provide the queryset to superclasses with the other model
return super().get_object(queryset=self.detail_model.objects.all())

def get_queryset(self):
# This only gets called by MultipleObjectMixin
pk = self.kwargs.get(self.pk_url_kwarg)
if pk is None:
raise AttributeError(
"Unable to filter on food truck: {} is missing in url.".format(
self.pk_url_kwarg
)
)
queryset = self.list_model.objects.filter(food_truck_id=pk)
# print(str(queryset.query))
return queryset

def get_context_data(self, **kwargs):
if "object" in kwargs:
kwargs[self.context_object_name] = kwargs["object"]
if "object_list" in kwargs:
kwargs[self.context_list_name] = kwargs["object_list"]

return super().get_context_data(**kwargs)

def get_form_kwargs(self):
# Bypass ModelFormMixin, which passes in self.object as instance if it
# is set.
return super(generic.edit.ModelFormMixin, self).get_form_kwargs()

And as a reference, this is what I changed the models to:

import uuid

from django.contrib.auth import get_user_model
from django.db import models
from django.utils import timezone

class FoodTruck(models.Model):
name = models.CharField(max_length=25)
category = models.CharField(max_length=20)
bio = models.TextField()
avatar_url = models.URLField(blank=True)
avatar_alt_text = models.CharField(max_length=20, blank=True)
avatar_title = models.CharField(max_length=20, blank=True)
cover_photo_url = models.URLField(blank=True)
cover_photo_alt_text = models.CharField(max_length=20, default="No photo provided")
cover_photo_title = models.CharField(max_length=20, default="No photo provided")
website = models.URLField(blank=True)
facebook = models.CharField(max_length=100, blank=True)
instagram = models.CharField(max_length=30, blank=True)
# https://9to5mac.com/2017/11/10/twitter-display-name-limit/
twitter = models.CharField(max_length=50, blank=True)

def __str__(self):
return self.name

class Review(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)
food_truck = models.ForeignKey(
FoodTruck, on_delete=models.CASCADE, related_name="reviews"
)
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
posted_at = models.DateTimeField(default=timezone.now)
speed_of_service = models.IntegerField()
quality_and_taste = models.IntegerField()
value_for_money = models.IntegerField()
comment = models.TextField(max_length=128)

def __str__(self):
return "Review about {} by {}".format(
self.food_truck.name, self.user.get_full_name()
)

And finally the form (with a bit of trickery to inject bootstrap classes):

class ReviewForm(forms.ModelForm):
def __init__(self, **kwargs):
super().__init__(**kwargs)
for field in self.fields.values():
if not field.widget.is_hidden:
field.widget.attrs.setdefault("class", "form-control")

class Meta:
model = Review
exclude = ("uuid", "user", "food_truck", "posted_at")

MVC Multiple Models in One View

You should create a view model as follows:

public class FooViewModel
{
public IEnumerable<LinkModel> Links { get; set; }
public IEnumerable<AboutModel> Abouts { get; set; }
public IEnumerable<PortfolioModel> Portfolios { get; set; }
public IEnumerable<SkillModel> Skills { get; set; }
}

Then from your controller populate them as to your requirements, as an example:

   public ActionResult Index()
{
var model = new FooViewModel();
model.Links = db.Links.ToList();
model.Abouts = db.Abouts.ToList();
model.Portfolios = db.Portfolios.ToList();
model.Skills = db.Skills.ToList();
return View(model);
}

Then change the model in your view to FooViewModel and all your properties will be available in there.

@model FooViewModel

<ul>
@foreach (var item in Model.Links)
{
<li>
@item
</li>
}
</ul>

<ul>
@foreach (var item in Model.Links)
{
<li>
@item
</li>
}
</ul>

// ....etc, obviously change the outputs as needed.

Multiple models in a view

There are lots of ways...

  1. with your BigViewModel
    you do:

    @model BigViewModel    
    @using(Html.BeginForm()) {
    @Html.EditorFor(o => o.LoginViewModel.Email)
    ...
    }
  2. you can create 2 additional views

    Login.cshtml

    @model ViewModel.LoginViewModel
    @using (Html.BeginForm("Login", "Auth", FormMethod.Post))
    {
    @Html.TextBoxFor(model => model.Email)
    @Html.PasswordFor(model => model.Password)
    }

    and register.cshtml same thing

    after creation you have to render them in the main view and pass them the viewmodel/viewdata

    so it could be like this:

    @{Html.RenderPartial("login", ViewBag.Login);}
    @{Html.RenderPartial("register", ViewBag.Register);}

    or

    @{Html.RenderPartial("login", Model.LoginViewModel)}
    @{Html.RenderPartial("register", Model.RegisterViewModel)}
  3. using ajax parts of your web-site become more independent

  4. iframes, but probably this is not the case

Two models in one view in ASP MVC 3

Create a parent view model that contains both models.

public class MainPageModel{
public Model1 Model1{get; set;}
public Model2 Model2{get; set;}
}

This way you can add additional models at a later date with very minimum effort.

Pass two models to view without using ViewModel approach

I guess you can use a Tuple<T1, T2>...

public ActionResult Index()
{
return View(new Tuple<Foo, Bar>(new Foo(), new Bar()));
}

View:

@model Tuple<Foo, Bar>

...

<div class="container">
Foo value = @Model.Item1.Value
<hr />
Bar value = @Model.Item2.Value
</div>

Live Demo



Related Topics



Leave a reply



Submit